diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj
index 4d50bb29..1f10ba45 100644
--- a/build/VStudio/winfsp_sys.vcxproj
+++ b/build/VStudio/winfsp_sys.vcxproj
@@ -152,6 +152,7 @@
+
diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters
index 29d159a0..ff94b395 100644
--- a/build/VStudio/winfsp_sys.vcxproj.filters
+++ b/build/VStudio/winfsp_sys.vcxproj.filters
@@ -86,6 +86,9 @@
Source
+
+ Source
+
diff --git a/src/sys/device.c b/src/sys/device.c
index c9341167..1c64de11 100644
--- a/src/sys/device.c
+++ b/src/sys/device.c
@@ -13,7 +13,7 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
DEVICE_TYPE DeviceType,
PDEVICE_OBJECT *PDeviceObject);
-VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
+NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject);
@@ -22,7 +22,6 @@ static BOOLEAN FspDeviceRetainAtDpcLevel(PDEVICE_OBJECT DeviceObject);
_IRQL_requires_(DISPATCH_LEVEL)
static VOID FspDeviceReleaseFromDpcLevel(PDEVICE_OBJECT DeviceObject);
static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject);
-static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject);
static IO_TIMER_ROUTINE FspFsvolDeviceTimerRoutine;
static WORKER_THREAD_ROUTINE FspFsvolDeviceExpirationRoutine;
@@ -49,10 +48,9 @@ VOID FspDeviceDeleteAll(VOID);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspDeviceCreateSecure)
#pragma alloc_text(PAGE, FspDeviceCreate)
-#pragma alloc_text(PAGE, FspDeviceInitComplete)
+#pragma alloc_text(PAGE, FspDeviceInitialize)
#pragma alloc_text(PAGE, FspDeviceDelete)
#pragma alloc_text(PAGE, FspFsvolDeviceInit)
-#pragma alloc_text(PAGE, FspFsvolDeviceInitComplete)
#pragma alloc_text(PAGE, FspFsvolDeviceFini)
#pragma alloc_text(PAGE, FspFsvolDeviceLockContext)
#pragma alloc_text(PAGE, FspFsvolDeviceUnlockContext)
@@ -79,6 +77,8 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
PDEVICE_OBJECT DeviceObject;
FSP_DEVICE_EXTENSION *DeviceExtension;
+ *PDeviceObject = 0;
+
switch (Kind)
{
case FspFsvolDeviceExtensionKind:
@@ -112,20 +112,7 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
DeviceExtension->RefCount = 1;
DeviceExtension->Kind = Kind;
- switch (Kind)
- {
- case FspFsvolDeviceExtensionKind:
- Result = FspFsvolDeviceInit(DeviceObject);
- break;
- case FspFsvrtDeviceExtensionKind:
- case FspFsctlDeviceExtensionKind:
- break;
- }
-
- if (!NT_SUCCESS(Result))
- IoDeleteDevice(DeviceObject);
- else
- *PDeviceObject = DeviceObject;
+ *PDeviceObject = DeviceObject;
return Result;
}
@@ -139,26 +126,31 @@ NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
return FspDeviceCreateSecure(Kind, ExtraSize, 0, DeviceType, 0, 0, PDeviceObject);
}
-VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject)
+NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject)
{
PAGED_CODE();
+ NTSTATUS Result;
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject);
switch (DeviceExtension->Kind)
{
case FspFsvolDeviceExtensionKind:
- FspFsvolDeviceInitComplete(DeviceObject);
+ Result = FspFsvolDeviceInit(DeviceObject);
break;
case FspFsvrtDeviceExtensionKind:
case FspFsctlDeviceExtensionKind:
+ Result = STATUS_SUCCESS;
break;
default:
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)
@@ -266,64 +258,64 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
NTSTATUS Result;
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")
- Result = IoInitializeTimer(DeviceObject, FspFsvolDeviceTimerRoutine, 0);
- if (!NT_SUCCESS(Result))
- return Result;
+ /*
+ * Volume device initialization is a mess, because of the different ways of
+ * creating/initializing different resources. So we will use some bits just
+ * to track what has been initialized!
+ */
- /* allocate a spare VPB in case we are mounted on a virtual disk */
- if (FILE_DEVICE_DISK_FILE_SYSTEM == DeviceObject->DeviceType)
+ /* is there a virtual disk? */
+ if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
{
+ /* allocate a spare VPB so that we can be mounted on the virtual disk */
FsvolDeviceExtension->SwapVpb = FspAllocNonPagedExternal(sizeof *FsvolDeviceExtension->SwapVpb);
if (0 == FsvolDeviceExtension->SwapVpb)
return STATUS_INSUFFICIENT_RESOURCES;
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 */
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 */
ExInitializeFastMutex(&FsvolDeviceExtension->GenericTableFastMutex);
RtlInitializeGenericTableAvl(&FsvolDeviceExtension->GenericTable,
FspFsvolDeviceCompareElement, FspFsvolDeviceAllocateElement, FspFsvolDeviceFreeElement, 0);
+ FsvolDeviceExtension->InitDoneGenTab = 1;
/* initialize the volume name buffer */
RtlInitEmptyUnicodeString(&FsvolDeviceExtension->VolumeName,
FsvolDeviceExtension->VolumeNameBuf, sizeof FsvolDeviceExtension->VolumeNameBuf);
- return STATUS_SUCCESS;
-}
-
-static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject)
-{
- 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);
+ /* 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);
+ if (!NT_SUCCESS(Result))
+ return Result;
KeInitializeSpinLock(&FsvolDeviceExtension->ExpirationLock);
ExInitializeWorkItem(&FsvolDeviceExtension->ExpirationWorkItem,
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);
+ FsvolDeviceExtension->InitDoneTimer = 1;
+
+ return STATUS_SUCCESS;
}
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
* retains our DeviceObject before queueing work items.
*/
- IoStopTimer(DeviceObject);
+ if (FsvolDeviceExtension->InitDoneTimer)
+ IoStopTimer(DeviceObject);
#if 0
/* 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.
* There is no need to protect accesses to the table as we are in the device destructor.
*/
- FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Element;
- while (0 != (Element = RtlGetElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, 0)))
- RtlDeleteElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, &Element->Identifier);
+ if (FsvolDeviceExtension->InitDoneGenTab)
+ {
+ FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Element;
+ while (0 != (Element = RtlGetElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, 0)))
+ RtlDeleteElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, &Element->Identifier);
+ }
#endif
- /*
- * Dereference the virtual volume device so that it can now go away.
- */
- if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
- ObDereferenceObject(FsvolDeviceExtension->FsvrtDeviceObject);
+ if (FsvolDeviceExtension->InitDoneIoq)
+ FspIoqDelete(FsvolDeviceExtension->Ioq);
/* finalize our delete lock */
- ExDeleteResourceLite(&FsvolDeviceExtension->DeleteResource);
+ if (FsvolDeviceExtension->InitDoneDelRsc)
+ ExDeleteResourceLite(&FsvolDeviceExtension->DeleteResource);
- /* free the spare VPB if we still have it */
- if (0 != FsvolDeviceExtension->SwapVpb)
- FspFreeExternal(FsvolDeviceExtension->SwapVpb);
+ /* is there a virtual disk? */
+ if (FsvolDeviceExtension->InitDoneFsvrt)
+ {
+ /* 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)
@@ -405,7 +406,7 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
KIRQL Irql;
- FspIoqRemoveExpired(&FsvolDeviceExtension->Ioq);
+ FspIoqRemoveExpired(FsvolDeviceExtension->Ioq);
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);
FsvolDeviceExtension->ExpirationInProgress = FALSE;
diff --git a/src/sys/dict.c b/src/sys/dict.c
new file mode 100644
index 00000000..57226f37
--- /dev/null
+++ b/src/sys/dict.c
@@ -0,0 +1,47 @@
+/**
+ * @file sys/dict.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+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;
+}
diff --git a/src/sys/driver.c b/src/sys/driver.c
index ce382ba9..b9b0cff3 100644
--- a/src/sys/driver.c
+++ b/src/sys/driver.c
@@ -39,8 +39,10 @@ NTSTATUS DriverEntry(
&FspFsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
FSP_RETURN(FspDeviceDelete(FspFsctlDiskDeviceObject));
- FspDeviceInitComplete(FspFsctlDiskDeviceObject);
- FspDeviceInitComplete(FspFsctlNetDeviceObject);
+ Result = FspDeviceInitialize(FspFsctlDiskDeviceObject);
+ ASSERT(STATUS_SUCCESS == Result);
+ Result = FspDeviceInitialize(FspFsctlNetDeviceObject);
+ ASSERT(STATUS_SUCCESS == Result);
/* setup the driver object */
DriverObject->DriverUnload = FspUnload;
diff --git a/src/sys/driver.h b/src/sys/driver.h
index e604a589..b03e59b8 100644
--- a/src/sys/driver.h
+++ b/src/sys/driver.h
@@ -127,7 +127,7 @@ extern __declspec(selectany) int bpglobal = 1;
/* if the IRP has not been marked pending already */\
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =\
FspFsvolDeviceExtension(DeviceObject);\
- if (!FspIoqPostIrp(&FsvolDeviceExtension->Ioq, Irp, &Result))\
+ if (!FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result))\
FspIopCompleteIrp(Irp, Result);\
} \
} \
@@ -291,12 +291,38 @@ VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem,
PWORKER_THREAD_ROUTINE Routine, PVOID Context);
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 */
-#define FspIrpTimestamp(Irp) \
- (*(ULONGLONG *)&(Irp)->Tail.Overlay.DriverContext[0])
- /* FspIrpTimestamp() uses up DriverContext[0] and [1] in 32-bit builds */
+typedef struct
+{
+ IO_CSQ_IRP_CONTEXT IoCsqIrpContext;
+ ULONGLONG ExpirationTime;
+} FSP_IRP_CONTEXT;
+#define FspIrpContext(Irp) \
+ (*(FSP_IRP_CONTEXT **)&(Irp)->Tail.Overlay.DriverContext[0])
#define FspIrpRequest(Irp) \
- (*(FSP_FSCTL_TRANSACT_REQ **)&(Irp)->Tail.Overlay.DriverContext[2])
+ (*(FSP_FSCTL_TRANSACT_REQ **)&(Irp)->Tail.Overlay.DriverContext[0])
/* I/O queue */
#define FspIoqTimeout ((PIRP)1)
@@ -307,12 +333,16 @@ typedef struct
KEVENT PendingIrpEvent;
LIST_ENTRY PendingIrpList, ProcessIrpList;
IO_CSQ PendingIoCsq, ProcessIoCsq;
+ FSP_DICT ProcessIrpDict;
LARGE_INTEGER IrpTimeout;
ULONG PendingIrpCapacity, PendingIrpCount;
VOID (*CompleteCanceledIrp)(PIRP Irp);
+ FSP_DICT_ENTRY *ProcessIrpDictBuckets[];
} FSP_IOQ;
-VOID FspIoqInitialize(FSP_IOQ *Ioq,
- PLARGE_INTEGER IrpTimeout, ULONG IrpCapacity, VOID (*CompleteCanceledIrp)(PIRP Irp));
+NTSTATUS FspIoqCreate(
+ ULONG IrpCapacity, PLARGE_INTEGER IrpTimeout, VOID (*CompleteCanceledIrp)(PIRP Irp),
+ FSP_IOQ **PIoq);
+VOID FspIoqDelete(FSP_IOQ *Ioq);
VOID FspIoqStop(FSP_IOQ *Ioq);
BOOLEAN FspIoqStopped(FSP_IOQ *Ioq);
VOID FspIoqRemoveExpired(FSP_IOQ *Ioq);
@@ -370,6 +400,7 @@ typedef struct
typedef struct
{
FSP_DEVICE_EXTENSION Base;
+ UINT32 InitDoneFsvrt:1, InitDoneDelRsc:1, InitDoneIoq:1, InitDoneGenTab:1, InitDoneTimer:1;
PDEVICE_OBJECT FsctlDeviceObject;
PDEVICE_OBJECT FsvrtDeviceObject;
HANDLE MupHandle;
@@ -377,7 +408,7 @@ typedef struct
FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem;
ERESOURCE DeleteResource;
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
- FSP_IOQ Ioq;
+ FSP_IOQ *Ioq;
KSPIN_LOCK ExpirationLock;
WORK_QUEUE_ITEM ExpirationWorkItem;
BOOLEAN ExpirationInProgress;
@@ -405,7 +436,7 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize,
NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize,
DEVICE_TYPE DeviceType,
PDEVICE_OBJECT *PDeviceObject);
-VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject);
+NTSTATUS FspDeviceInitialize(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject);
BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject);
VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject);
diff --git a/src/sys/iop.c b/src/sys/iop.c
index 3776e27b..60c78131 100644
--- a/src/sys/iop.c
+++ b/src/sys/iop.c
@@ -29,6 +29,7 @@ VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
typedef struct
{
+ FSP_IRP_CONTEXT IrpContext;
FSP_IOP_REQUEST_FINI *RequestFini;
PVOID Context[3];
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) UINT8 RequestBuf[];
diff --git a/src/sys/ioq.c b/src/sys/ioq.c
index db9464b9..50073e03 100644
--- a/src/sys/ioq.c
+++ b/src/sys/ioq.c
@@ -91,21 +91,19 @@ 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 (Head == Entry)
+ return 0;
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;
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;
+ ULONGLONG ExpirationTime = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->ExpirationTime;
+ return FspIrpContext(Irp)->ExpirationTime <= ExpirationTime ?
+ CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 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)
@@ -134,11 +132,19 @@ static NTSTATUS FspIoqProcessInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertCo
if (Ioq->Stopped)
return STATUS_CANCELLED;
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;
}
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);
}
@@ -149,27 +155,22 @@ static PIRP FspIoqProcessPeekNextIrp(PIO_CSQ IoCsq, PIRP Irp, PVOID PeekContext)
return 0;
PLIST_ENTRY Head = &Ioq->ProcessIrpList;
PLIST_ENTRY Entry = 0 == Irp ? Head->Flink : Irp->Tail.Overlay.ListEntry.Flink;
+ if (Head == Entry)
+ return 0;
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;
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;
+ ULONGLONG ExpirationTime = ((FSP_IOQ_PEEK_CONTEXT *)PeekContext)->ExpirationTime;
+ return FspIrpContext(Irp)->ExpirationTime <= ExpirationTime ?
+ CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry) : 0;
}
- for (; Head != Entry; Entry = Entry->Flink)
+ else
{
- Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
- if (Irp == IrpHint)
- return Irp;
+ FSP_DICT_ENTRY *DictEntry = FspDictGetEntry(&Ioq->ProcessIrpDict, IrpHint);
+ return 0 != DictEntry ? (PIRP)IrpHint : 0;
}
- return 0;
}
_IRQL_raises_(DISPATCH_LEVEL)
@@ -192,11 +193,28 @@ static VOID FspIoqProcessCompleteCanceledIrp(PIO_CSQ IoCsq, PIRP Irp)
Ioq->CompleteCanceledIrp(Irp);
}
-VOID FspIoqInitialize(FSP_IOQ *Ioq,
- PLARGE_INTEGER IrpTimeout, ULONG IrpCapacity, VOID (*CompleteCanceledIrp)(PIRP Irp))
+BOOLEAN FspIoqIrpEquals(PVOID Irp1, PVOID Irp2)
+{
+ 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);
+ 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);
KeInitializeSpinLock(&Ioq->SpinLock);
KeInitializeEvent(&Ioq->PendingIrpEvent, NotificationEvent, FALSE);
@@ -216,9 +234,19 @@ VOID FspIoqInitialize(FSP_IOQ *Ioq,
FspIoqProcessAcquireLock,
FspIoqProcessReleaseLock,
FspIoqProcessCompleteCanceledIrp);
+ FspDictInitialize(&Ioq->ProcessIrpDict,
+ FspIoqIrpEquals, FspIoqIrpHash, Ioq->ProcessIrpDictBuckets, BucketCount);
Ioq->IrpTimeout = *IrpTimeout;
Ioq->PendingIrpCapacity = IrpCapacity;
Ioq->CompleteCanceledIrp = CompleteCanceledIrp;
+
+ return STATUS_SUCCESS;
+}
+
+VOID FspIoqDelete(FSP_IOQ *Ioq)
+{
+ FspIoqStop(Ioq);
+ FspFree(Ioq);
}
VOID FspIoqStop(FSP_IOQ *Ioq)
@@ -261,7 +289,7 @@ VOID FspIoqRemoveExpired(FSP_IOQ *Ioq)
BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp, NTSTATUS *PResult)
{
NTSTATUS Result;
- FspIrpTimestamp(Irp) = KeQueryInterruptTime() + Ioq->IrpTimeout.QuadPart;
+ FspIrpContext(Irp)->ExpirationTime = KeQueryInterruptTime() + Ioq->IrpTimeout.QuadPart;
Result = IoCsqInsertIrpEx(&Ioq->PendingIoCsq, Irp, 0, (PVOID)1);
if (NT_SUCCESS(Result))
return TRUE;
diff --git a/src/sys/volume.c b/src/sys/volume.c
index 6f5c9d36..79febc46 100644
--- a/src/sys/volume.c
+++ b/src/sys/volume.c
@@ -158,9 +158,18 @@ NTSTATUS FspVolumeCreate(
FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject;
FsvolDeviceExtension->VolumeParams = VolumeParams;
RtlCopyUnicodeString(&FsvolDeviceExtension->VolumeName, &VolumeName);
- FspDeviceInitComplete(FsvolDeviceObject);
- if (0 != FsvrtDeviceObject)
- FspDeviceInitComplete(FsvrtDeviceObject);
+ Result = FspDeviceInitialize(FsvolDeviceObject);
+ if (NT_SUCCESS(Result))
+ {
+ if (0 != FsvrtDeviceObject)
+ Result = FspDeviceInitialize(FsvrtDeviceObject);
+ }
+ if (!NT_SUCCESS(Result))
+ {
+ if (0 != FsvrtDeviceObject)
+ FspDeviceRelease(FsvrtDeviceObject);
+ FspDeviceRelease(FsvolDeviceObject);
+ }
/* do we need to register with MUP? */
if (0 == FsvrtDeviceObject)
@@ -220,7 +229,7 @@ VOID FspVolumeDelete(
ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE);
/* stop the I/O queue */
- FspIoqStop(&FsvolDeviceExtension->Ioq);
+ FspIoqStop(FsvolDeviceExtension->Ioq);
/* do we have a virtual disk device or a MUP handle? */
if (0 != FsvolDeviceExtension->FsvrtDeviceObject)
@@ -356,7 +365,7 @@ NTSTATUS FspVolumeMount(
if (FsvolDeviceExtension->FsvrtDeviceObject == FsvrtDeviceObject)
{
ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE);
- if (!FspIoqStopped(&FsvolDeviceExtension->Ioq))
+ if (!FspIoqStopped(FsvolDeviceExtension->Ioq))
{
Result = STATUS_SUCCESS;
/* break out of the loop without FspDeviceRelease or DeleteResource release! */
@@ -423,7 +432,7 @@ NTSTATUS FspVolumeRedirQueryPathEx(
ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->DeleteResource, TRUE);
Result = STATUS_BAD_NETWORK_PATH;
- if (!FspIoqStopped(&FsvolDeviceExtension->Ioq))
+ if (!FspIoqStopped(FsvolDeviceExtension->Ioq))
{
RtlInitUnicodeString(&Prefix, FsvolDeviceExtension->VolumeParams.Prefix);
if (Prefix.Length <= QueryPathRequest->PathName.Length &&
@@ -515,7 +524,7 @@ NTSTATUS FspVolumeTransact(
if (0 == NextResponse)
break;
- ProcessIrp = FspIoqEndProcessingIrp(&FsvolDeviceExtension->Ioq, (UINT_PTR)Response->Hint);
+ ProcessIrp = FspIoqEndProcessingIrp(FsvolDeviceExtension->Ioq, (UINT_PTR)Response->Hint);
if (0 == ProcessIrp)
/* either IRP was canceled or a bogus Hint was provided */
continue;
@@ -538,9 +547,9 @@ NTSTATUS FspVolumeTransact(
KeQuerySystemTime(&Timeout);
Timeout.QuadPart += FsvolDeviceExtension->VolumeParams.TransactTimeout * 10000;
/* 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;
}
if (FspIoqTimeout == PendingIrp)
@@ -565,7 +574,7 @@ NTSTATUS FspVolumeTransact(
RtlCopyMemory(Request, PendingIrpRequest, 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
@@ -573,7 +582,7 @@ NTSTATUS FspVolumeTransact(
* queues of the Ioq will be cancelled during FspIoqStop(). We must
* also cancel the PendingIrp we have in our hands.
*/
- ASSERT(FspIoqStopped(&FsvolDeviceExtension->Ioq));
+ ASSERT(FspIoqStopped(FsvolDeviceExtension->Ioq));
FspIopCompleteIrp(PendingIrp, STATUS_CANCELLED);
return STATUS_CANCELLED;
}
@@ -583,7 +592,7 @@ NTSTATUS FspVolumeTransact(
break;
}
- PendingIrp = FspIoqNextPendingIrp(&FsvolDeviceExtension->Ioq, 0);
+ PendingIrp = FspIoqNextPendingIrp(FsvolDeviceExtension->Ioq, 0);
if (0 == PendingIrp)
break;
}
@@ -619,7 +628,7 @@ NTSTATUS FspVolumeWork(
* so that we can disassociate the Request on failure and release ownership
* back to the caller.
*/
- if (!FspIoqPostIrp(&FsvolDeviceExtension->Ioq, Irp, &Result))
+ if (!FspIoqPostIrp(FsvolDeviceExtension->Ioq, Irp, &Result))
{
Request->Hint = 0;
FspIrpRequest(Irp) = 0;