diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj
index b20b231b..b0d0a3d4 100644
--- a/build/VStudio/winfsp_sys.vcxproj
+++ b/build/VStudio/winfsp_sys.vcxproj
@@ -148,6 +148,7 @@
+
diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters
index 07e25c08..cab112ad 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/create.c b/src/sys/create.c
index eb2c954c..8fe60269 100644
--- a/src/sys/create.c
+++ b/src/sys/create.c
@@ -572,16 +572,16 @@ static VOID FspFsvolCreateClose(
/*
* This routine handles the case where we must close an open file,
* because of a failure during Create completion. We simply create
- * a CreateClose request and we post it to our Ioq.
+ * a CreateClose request and we post it as a work item.
*
* Ideally there would be no failure modes for this routine. Reality is
* different.
*
* The more serious (but perhaps non-existent in practice) failure is a
- * memory allocation failure for the CreateClose request. In this case we
- * will leak the user-mode file system handle!
+ * memory allocation failure. In this case we will leak the user-mode
+ * file system handle!
*
- * This routine may also fail if the Ioq was stopped, which means that
+ * This routine may also fail if we cannot post a work item, which means that
* the virtual volume device and the file system volume device are being
* deleted. Because it is assumed that only the user-mode file system would
* initiate a device deletion, this case is more benign (presumably the file
@@ -600,30 +600,29 @@ static VOID FspFsvolCreateClose(
FSP_FSCTL_TRANSACT_REQ *Request;
/* create the user-mode file system request */
- Result = FspIopCreateRequest(Irp, FileNameRequired ? &FsContext->FileName : 0, 0, &Request);
+ Result = FspIopCreateRequest(0, FileNameRequired ? &FsContext->FileName : 0, 0, &Request);
if (!NT_SUCCESS(Result))
- {
- DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%p: "
- "FspIopCreateRequest failed: the user-mode file system handle will be leaked!",
- IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName,
- FsContext->UserContext, FileObject->FsContext2);
- goto exit;
- }
+ goto leak_exit;
- /* populate the Create request */
+ /* populate the CreateClose request */
Request->Kind = FspFsctlTransactCreateCloseKind;
Request->Req.Close.UserContext = FsContext->UserContext;
Request->Req.Close.UserContext2 = (UINT_PTR)FileObject->FsContext2;
- /*
- * Post the IRP to our Ioq.
- */
- if (!FspIoqPostIrp(&FsvrtDeviceExtension->Ioq, Irp))
- {
- /* this can only happen if the Ioq was stopped */
- ASSERT(FspIoqStopped(&FsvrtDeviceExtension->Ioq));
- goto exit;
- }
+ /* post as a work request */
+ if (!FspIopPostWorkRequest(DeviceObject, Request))
+ /* no need to delete the request here as FspIopPostWorkRequest() will do so in all cases */
+ goto leak_exit;
+
+ goto exit;
+
+leak_exit:;
+#if DBG
+ DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%p: "
+ "error: the user-mode file system handle will be leaked!",
+ IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName,
+ FsContext->UserContext, FileObject->FsContext2);
+#endif
exit:
FspFileContextDelete(FsContext);
diff --git a/src/sys/debug.c b/src/sys/debug.c
index aae2ace2..05a34ed3 100644
--- a/src/sys/debug.c
+++ b/src/sys/debug.c
@@ -167,6 +167,7 @@ const char *IoctlCodeSym(ULONG ControlCode)
SYM(FSP_FSCTL_CREATE)
SYM(FSP_FSCTL_DELETE)
SYM(FSP_FSCTL_TRANSACT)
+ SYM(FSP_FSCTL_WORK)
default:
return "IOCTL:Unknown";
}
diff --git a/src/sys/driver.c b/src/sys/driver.c
index ece30358..f4f73c3d 100644
--- a/src/sys/driver.c
+++ b/src/sys/driver.c
@@ -56,6 +56,7 @@ NTSTATUS DriverEntry(
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = FspDirectoryControl;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFileSystemControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FspDeviceControl;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = FspInternalDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = FspShutdown;
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = FspLockControl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FspCleanup;
@@ -80,6 +81,7 @@ NTSTATUS DriverEntry(
FspIopCompleteFunction[IRP_MJ_DIRECTORY_CONTROL] = FspDirectoryControlComplete;
FspIopCompleteFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFileSystemControlComplete;
FspIopCompleteFunction[IRP_MJ_DEVICE_CONTROL] = FspDeviceControlComplete;
+ FspIopCompleteFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = FspFsvolInternalDeviceControlComplete;
FspIopCompleteFunction[IRP_MJ_SHUTDOWN] = FspShutdownComplete;
FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspLockControlComplete;
FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspCleanupComplete;
diff --git a/src/sys/driver.h b/src/sys/driver.h
index 667b8221..e7115af5 100644
--- a/src/sys/driver.h
+++ b/src/sys/driver.h
@@ -187,6 +187,7 @@ _Dispatch_type_(IRP_MJ_DEVICE_CONTROL) FSP_DRIVER_DISPATCH FspDeviceControl;
_Dispatch_type_(IRP_MJ_DIRECTORY_CONTROL) FSP_DRIVER_DISPATCH FspDirectoryControl;
_Dispatch_type_(IRP_MJ_FILE_SYSTEM_CONTROL) FSP_DRIVER_DISPATCH FspFileSystemControl;
_Dispatch_type_(IRP_MJ_FLUSH_BUFFERS) FSP_DRIVER_DISPATCH FspFlushBuffers;
+_Dispatch_type_(IRP_MJ_INTERNAL_DEVICE_CONTROL) FSP_DRIVER_DISPATCH FspInternalDeviceControl;
_Dispatch_type_(IRP_MJ_LOCK_CONTROL) FSP_DRIVER_DISPATCH FspLockControl;
_Dispatch_type_(IRP_MJ_QUERY_EA) FSP_DRIVER_DISPATCH FspQueryEa;
_Dispatch_type_(IRP_MJ_QUERY_INFORMATION) FSP_DRIVER_DISPATCH FspQueryInformation;
@@ -217,6 +218,7 @@ FSP_IOCMPL_DISPATCH FspDeviceControlComplete;
FSP_IOCMPL_DISPATCH FspDirectoryControlComplete;
FSP_IOCMPL_DISPATCH FspFileSystemControlComplete;
FSP_IOCMPL_DISPATCH FspFlushBuffersComplete;
+FSP_IOCMPL_DISPATCH FspFsvolInternalDeviceControlComplete;
FSP_IOCMPL_DISPATCH FspLockControlComplete;
FSP_IOCMPL_DISPATCH FspQueryEaComplete;
FSP_IOCMPL_DISPATCH FspQueryInformationComplete;
@@ -259,8 +261,11 @@ BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp);
PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint);
/* I/O processing */
+#define FSP_FSCTL_WORK \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'W', METHOD_NEITHER, FILE_ANY_ACCESS)
NTSTATUS FspIopCreateRequest(
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_FSCTL_TRANSACT_REQ **PRequest);
+NTSTATUS FspIopPostWorkRequest(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_TRANSACT_REQ *Request);
VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceRelease);
static inline
VOID FspIopCompleteIrp(PIRP Irp, NTSTATUS Result)
diff --git a/src/sys/idevctl.c b/src/sys/idevctl.c
new file mode 100644
index 00000000..adede96a
--- /dev/null
+++ b/src/sys/idevctl.c
@@ -0,0 +1,98 @@
+/**
+ * @file sys/idevctl.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+static NTSTATUS FspFsvolInternalDeviceControl(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
+FSP_IOCMPL_DISPATCH FspFsvolInternalDeviceControlComplete;
+FSP_DRIVER_DISPATCH FspInternalDeviceControl;
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, FspFsvolInternalDeviceControl)
+#pragma alloc_text(PAGE, FspFsvolInternalDeviceControlComplete)
+#pragma alloc_text(PAGE, FspInternalDeviceControl)
+#endif
+
+static NTSTATUS FspFsvolInternalDeviceControl(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+ PAGED_CODE();
+
+ NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case FSP_FSCTL_WORK:
+ {
+ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
+ PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject;
+
+ if (!FspDeviceRetain(FsvrtDeviceObject))
+ return STATUS_CANCELLED;
+ try
+ {
+ FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension =
+ FspFsvrtDeviceExtension(FsvrtDeviceObject);
+ FSP_FSCTL_TRANSACT_REQ *Request = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+
+ ASSERT(0 == Request->Hint);
+
+ /* associate the passed Request with our Irp; acquire ownership of the Request */
+ Request->Hint = (UINT_PTR)Irp;
+ Irp->Tail.Overlay.DriverContext[0] = Request;
+
+ if (!FspIoqPostIrp(&FsvrtDeviceExtension->Ioq, Irp))
+ {
+ /* this can only happen if the Ioq was stopped */
+ ASSERT(FspIoqStopped(&FsvrtDeviceExtension->Ioq));
+
+ /* disocciate the Request from our Irp; release ownership back to caller */
+ Request->Hint = 0;
+ Irp->Tail.Overlay.DriverContext[0] = 0;
+
+ Result = STATUS_CANCELLED;
+ goto exit;
+ }
+
+ Result = STATUS_PENDING;
+
+ exit:;
+ }
+ finally
+ {
+ FspDeviceRelease(FsvrtDeviceObject);
+ }
+ }
+ break;
+ }
+ return Result;
+}
+
+VOID FspFsvolInternalDeviceControlComplete(
+ PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
+{
+ FSP_ENTER_IOC(PAGED_CODE());
+
+ FSP_LEAVE_IOC("%s", IoctlCodeSym(IrpSp->Parameters.DeviceIoControl.IoControlCode));
+}
+
+NTSTATUS FspInternalDeviceControl(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ FSP_ENTER_MJ(PAGED_CODE());
+
+ ASSERT(IRP_MJ_INTERNAL_DEVICE_CONTROL == IrpSp->MajorFunction);
+
+ switch (FspDeviceExtension(DeviceObject)->Kind)
+ {
+ case FspFsvolDeviceExtensionKind:
+ FSP_RETURN(Result = FspFsvolInternalDeviceControl(DeviceObject, Irp, IrpSp));
+ default:
+ FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST);
+ }
+
+ FSP_LEAVE_MJ("%s", IoctlCodeSym(IrpSp->Parameters.DeviceIoControl.IoControlCode));
+}
diff --git a/src/sys/iop.c b/src/sys/iop.c
index 02fe38e0..a835d038 100644
--- a/src/sys/iop.c
+++ b/src/sys/iop.c
@@ -8,11 +8,14 @@
NTSTATUS FspIopCreateRequest(
PIRP Irp, PUNICODE_STRING FileName, ULONG ExtraSize, FSP_FSCTL_TRANSACT_REQ **PRequest);
+NTSTATUS FspIopPostWorkRequest(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_TRANSACT_REQ *Request);
+static IO_COMPLETION_ROUTINE FspIopPostWorkRequestCompletion;
NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request);
VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FspIopCreateRequest)
+#pragma alloc_text(PAGE, FspIopPostWorkRequest)
#pragma alloc_text(PAGE, FspIopDispatchPrepare)
#pragma alloc_text(PAGE, FspIopDispatchComplete)
#endif
@@ -54,12 +57,67 @@ NTSTATUS FspIopCreateRequest(
Request->FileName.Size = 0;
}
- Irp->Tail.Overlay.DriverContext[0] = Request;
+ if (0 != Irp)
+ Irp->Tail.Overlay.DriverContext[0] = Request;
*PRequest = Request;
return STATUS_SUCCESS;
}
+static inline
+VOID FspIopDeleteRequest(FSP_FSCTL_TRANSACT_REQ *Request)
+{
+ ExFreePoolWithTag(Request, FSP_TAG);
+}
+
+NTSTATUS FspIopPostWorkRequest(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_TRANSACT_REQ *Request)
+{
+ PAGED_CODE();
+
+ ASSERT(0 == Request->Hint);
+
+ NTSTATUS Result;
+ PIRP Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+ if (0 == Irp)
+ {
+ Result = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ PIO_STACK_LOCATION IrpSp = IoGetNextIrpStackLocation(Irp);
+ IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ IrpSp->Parameters.DeviceIoControl.IoControlCode = FSP_FSCTL_WORK;
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength = Request->Size;
+ IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = Request;
+
+ ASSERT(METHOD_NEITHER == (IrpSp->Parameters.DeviceIoControl.IoControlCode & 3));
+
+ IoSetCompletionRoutine(Irp, FspIopPostWorkRequestCompletion, 0, TRUE, TRUE, TRUE);
+
+ Result = IoCallDriver(DeviceObject, Irp);
+ if (STATUS_PENDING == Result)
+ return STATUS_SUCCESS;
+
+ /*
+ * If we did not receive STATUS_PENDING, we still own the Request and must delete it!
+ */
+
+exit:
+ FspIopDeleteRequest(Request);
+
+ return Result;
+}
+
+static NTSTATUS FspIopPostWorkRequestCompletion(
+ PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
+{
+ // !PAGED_CODE();
+
+ IoFreeIrp(Irp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceRelease)
{
// !PAGED_CODE();
@@ -69,7 +127,7 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceRelease)
if (0 != Irp->Tail.Overlay.DriverContext[0])
{
- ExFreePoolWithTag(Irp->Tail.Overlay.DriverContext[0], FSP_TAG);
+ FspIopDeleteRequest(Irp->Tail.Overlay.DriverContext[0]);
Irp->Tail.Overlay.DriverContext[0] = 0;
}