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; }