From 892e8eb02574298cb777b31ba3073d0588b32870 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 23 Feb 2016 20:07:33 -0800 Subject: [PATCH] sys: wq: FspWq* routiens sys: write: initial implementation --- build/VStudio/winfsp_sys.vcxproj | 1 + build/VStudio/winfsp_sys.vcxproj.filters | 3 + src/sys/driver.h | 25 +++++ src/sys/util.c | 52 +++++++++- src/sys/wq.c | 74 +++++++++++++ src/sys/write.c | 126 ++++++++++++++++++++++- 6 files changed, 275 insertions(+), 6 deletions(-) create mode 100644 src/sys/wq.c diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index 1e294054..be0b5c33 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -170,6 +170,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index a1f3c966..0e7f66eb 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -89,6 +89,9 @@ Source + + Source + diff --git a/src/sys/driver.h b/src/sys/driver.h index ae63da56..abbc73f9 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -322,10 +322,15 @@ PVOID FspAllocateIrpMustSucceed(CCHAR StackSize); BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams); VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); NTSTATUS FspCreateGuid(GUID *Guid); +NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, + KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl); NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes); +NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain); NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor); +#define FspSetTopLevelIrp(Irp) (IoGetTopLevelIrp() ? FALSE : (IoSetTopLevelIrp(Irp), TRUE)) +#define FspResetTopLevelIrp(TopLevel) ((TopLevel) ? IoSetTopLevelIrp(0) : (void)0) /* utility: synchronous work queue */ typedef struct @@ -431,6 +436,8 @@ enum FspIopCreateRequestFunnel(I, F, E, 0, FspIopRequestMustSucceed, P) #define FspIopCreateRequestEx(I, F, E, RF, P)\ FspIopCreateRequestFunnel(I, F, E, RF, 0, P) +#define FspIopCreateRequestWorkItem(I, E, RF, P)\ + FspIopCreateRequestFunnel(I, 0, E, RF, FspIopRequestNonPaged, P) #define FspIopRequestContext(Request, I)\ (*FspIopRequestContextAddress(Request, I)) #define FspIopPostWorkRequest(D, R) FspIopPostWorkRequestFunnel(D, R, FALSE) @@ -454,6 +461,24 @@ FSP_FSCTL_TRANSACT_RSP *FspIopIrpResponse(PIRP Irp); NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request); NTSTATUS FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); +/* work queue processing */ +enum +{ + FspWqRequestIrpAndFlags = 0, + FspWqRequestWorkRoutine = 1, +}; +typedef NTSTATUS FSP_WQ_REQUEST_WORK( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + BOOLEAN CanWait); +NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp, + FSP_WQ_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini, + BOOLEAN CreateAndPost); +VOID FspWqPostIrpWorkItem(PIRP Irp); +#define FspWqCreateIrpWorkItem(I, RW, RF)\ + FspWqCreateAndPostIrpWorkItem(I, RW, RF, FALSE) +#define FspWqRepostIrpWorkItem(I, RW, RF)\ + FspWqCreateAndPostIrpWorkItem(I, RW, RF, TRUE) + /* device management */ #define FSP_DEVICE_VOLUME_NAME_LENMAX (FSP_FSCTL_VOLUME_NAME_SIZEMAX - sizeof(WCHAR)) enum diff --git a/src/sys/util.c b/src/sys/util.c index f76206b9..eadc4f60 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -9,7 +9,10 @@ BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, BOOLEAN AllowStreams); VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); NTSTATUS FspCreateGuid(GUID *Guid); +NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, + KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl); NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes); +NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain); NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor); @@ -26,7 +29,9 @@ static KDEFERRED_ROUTINE FspQueueDelayedWorkItemDPC; #pragma alloc_text(PAGE, FspUnicodePathIsValid) #pragma alloc_text(PAGE, FspUnicodePathSuffix) #pragma alloc_text(PAGE, FspCreateGuid) +#pragma alloc_text(PAGE, FspLockUserBuffer) #pragma alloc_text(PAGE, FspCcSetFileSizes) +#pragma alloc_text(PAGE, FspCcMdlWriteComplete) #pragma alloc_text(PAGE, FspQuerySecurityDescriptorInfo) #pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem) #pragma alloc_text(PAGE, FspExecuteSynchronousWorkItem) @@ -153,6 +158,31 @@ NTSTATUS FspCreateGuid(GUID *Guid) return Result; } +NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, + KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl) +{ + PAGED_CODE(); + + *PMdl = 0; + + PMDL Mdl = IoAllocateMdl(UserBuffer, Length, FALSE, FALSE, 0); + if (0 == Mdl) + return STATUS_INSUFFICIENT_RESOURCES; + + try + { + MmProbeAndLockPages(Mdl, RequestorMode, Operation); + } + except (EXCEPTION_EXECUTE_HANDLER) + { + IoFreeMdl(Mdl); + return GetExceptionCode(); + } + + *PMdl = Mdl; + return STATUS_SUCCESS; +} + NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes) { PAGED_CODE(); @@ -162,12 +192,28 @@ NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes) CcSetFileSizes(FileObject, FileSizes); return STATUS_SUCCESS; } - except(EXCEPTION_EXECUTE_HANDLER) + except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } +NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain) +{ + PAGED_CODE(); + + try + { + CcMdlWriteComplete(FileObject, FileOffset, MdlChain); + return STATUS_SUCCESS; + } + except (EXCEPTION_EXECUTE_HANDLER) + { + CcMdlWriteAbort(FileObject, MdlChain); + return GetExceptionCode(); + } +} + NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor) @@ -200,16 +246,18 @@ VOID FspInitializeSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWork ExInitializeWorkItem(&SynchronousWorkItem->WorkQueueItem, FspExecuteSynchronousWorkItemRoutine, SynchronousWorkItem); } + VOID FspExecuteSynchronousWorkItem(FSP_SYNCHRONOUS_WORK_ITEM *SynchronousWorkItem) { PAGED_CODE(); - ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, DelayedWorkQueue); + ExQueueWorkItem(&SynchronousWorkItem->WorkQueueItem, CriticalWorkQueue); NTSTATUS Result; Result = KeWaitForSingleObject(&SynchronousWorkItem->Event, Executive, KernelMode, FALSE, 0); ASSERT(STATUS_SUCCESS == Result); } + static VOID FspExecuteSynchronousWorkItemRoutine(PVOID Context) { PAGED_CODE(); diff --git a/src/sys/wq.c b/src/sys/wq.c new file mode 100644 index 00000000..a802af01 --- /dev/null +++ b/src/sys/wq.c @@ -0,0 +1,74 @@ +/** + * @file sys/wq.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +static VOID FspWqWorkRoutine(PVOID Context); + +NTSTATUS FspWqCreateAndPostIrpWorkItem(PIRP Irp, + FSP_WQ_REQUEST_WORK *WorkRoutine, FSP_IOP_REQUEST_FINI *RequestFini, + BOOLEAN CreateAndPost) +{ + FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp); + + if (0 == RequestWorkItem) + { + NTSTATUS Result = FspIopCreateRequestWorkItem(Irp, sizeof(WORK_QUEUE_ITEM), + RequestFini, &RequestWorkItem); + if (!NT_SUCCESS(Result)) + return Result; + + ASSERT(sizeof(FSP_WQ_REQUEST_WORK *) == sizeof(PVOID)); + + PIRP TopLevelIrp = IoGetTopLevelIrp(); + FspIopRequestContext(RequestWorkItem, FspWqRequestIrpAndFlags) = + (PVOID)((UINT_PTR)Irp | (0 == TopLevelIrp || Irp == TopLevelIrp)); + FspIopRequestContext(RequestWorkItem, FspWqRequestWorkRoutine) = + (PVOID)(UINT_PTR)WorkRoutine; + ExInitializeWorkItem((PWORK_QUEUE_ITEM)&RequestWorkItem->Buffer, FspWqWorkRoutine, Irp); + } + + if (!CreateAndPost) + return STATUS_SUCCESS; + + FspWqPostIrpWorkItem(Irp); + return STATUS_PENDING; +} + +VOID FspWqPostIrpWorkItem(PIRP Irp) +{ + FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp); + + ASSERT(RequestWorkItem->Kind == FspFsctlTransactReservedKind); + ASSERT(RequestWorkItem->Size == sizeof *RequestWorkItem + sizeof(WORK_QUEUE_ITEM)); + ASSERT(RequestWorkItem->Hint == (UINT_PTR)Irp); + + IoMarkIrpPending(Irp); + ExQueueWorkItem((PWORK_QUEUE_ITEM)&RequestWorkItem->Buffer, CriticalWorkQueue); +} + +static VOID FspWqWorkRoutine(PVOID Context) +{ + PIRP Irp = Context; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp); + BOOLEAN TopLevel = (BOOLEAN) + ((UINT_PTR)FspIopRequestContext(RequestWorkItem, FspWqRequestIrpAndFlags) & 1); + FSP_WQ_REQUEST_WORK *WorkRoutine = (FSP_WQ_REQUEST_WORK *)(UINT_PTR) + FspIopRequestContext(RequestWorkItem, FspWqRequestWorkRoutine); + NTSTATUS Result; + + IoSetTopLevelIrp(TopLevel ? Irp : (PIRP)FSRTL_FSP_TOP_LEVEL_IRP); + + Result = WorkRoutine(IrpSp->DeviceObject, Irp, IrpSp, FALSE); + if (STATUS_PENDING != Result) + { + DEBUGLOGIRP(Irp, Result); + FspIopCompleteIrp(Irp, Result); + } + + IoSetTopLevelIrp(0); +} diff --git a/src/sys/write.c b/src/sys/write.c index e7628a64..6e554a55 100644 --- a/src/sys/write.c +++ b/src/sys/write.c @@ -7,18 +7,124 @@ #include static NTSTATUS FspFsvolWrite( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvolWriteCached( + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + BOOLEAN CanWait); +static VOID FspFsvolWriteCachedDeferred(PVOID Context1, PVOID Context2); +static NTSTATUS FspFsvolWriteNonCached( + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; FSP_DRIVER_DISPATCH FspWrite; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolWrite) +#pragma alloc_text(PAGE, FspFsvolWriteCached) +#pragma alloc_text(PAGE, FspFsvolWriteCachedDeferred) +#pragma alloc_text(PAGE, FspFsvolWriteNonCached) #pragma alloc_text(PAGE, FspFsvolWriteComplete) #pragma alloc_text(PAGE, FspWrite) #endif static NTSTATUS FspFsvolWrite( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + /* is this a valid FileObject? */ + if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext)) + return STATUS_INVALID_DEVICE_REQUEST; + + NTSTATUS Result; + BOOLEAN TopLevel = FspSetTopLevelIrp(Irp); + + /* is this an MDL complete request? */ + if (FlagOn(IrpSp->MinorFunction, IRP_MN_COMPLETE)) + { + Result = FspCcMdlWriteComplete(IrpSp->FileObject, + &IrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress); + Irp->MdlAddress = 0; + goto exit; + } + + /* do we have anything to write? */ + if (0 == IrpSp->Parameters.Write.Length) + { + Irp->IoStatus.Information = 0; + Result = STATUS_SUCCESS; + goto exit; + } + + /* probe and lock the user buffer */ + if (0 == Irp->MdlAddress) + { + Result = FspLockUserBuffer(Irp->UserBuffer, IrpSp->Parameters.Write.Length, + Irp->RequestorMode, IoReadAccess, &Irp->MdlAddress); + if (!NT_SUCCESS(Result)) + goto exit; + } + + if (!FlagOn(Irp->Flags, IRP_NOCACHE)) + Result = FspFsvolWriteCached(FsvolDeviceObject, Irp, IrpSp, IoIsOperationSynchronous(Irp)); + else + Result = FspFsvolWriteNonCached(FsvolDeviceObject, Irp, IrpSp); + +exit: + FspResetTopLevelIrp(TopLevel); + + return Result; +} + +static NTSTATUS FspFsvolWriteCached( + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, + BOOLEAN CanWait) +{ + PAGED_CODE(); + + NTSTATUS Result; + FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp); + PFILE_OBJECT FileObject = IrpSp->FileObject; + FSP_FILE_NODE *FileNode = FileObject->FsContext; + FSP_FILE_DESC *FileDesc = FileObject->FsContext2; +#if 0 + ULONG WriteKey = IrpSp->Parameters.Write.Key; + LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset; +#endif + ULONG WriteLength = IrpSp->Parameters.Write.Length; +#if 0 + BOOLEAN WriteToEof = + FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; +#endif + + ASSERT(FileNode == FileDesc->FileNode); + + /* should we defer the write? */ + if (DEBUGRANDTEST(10, TRUE) || + !CcCanIWrite(FileObject, WriteLength, CanWait, 0 != RequestWorkItem)) + { + Result = FspWqCreateIrpWorkItem(Irp, FspFsvolWriteCached, 0); + if (NT_SUCCESS(Result)) + { + IoMarkIrpPending(Irp); + CcDeferWrite(FileObject, FspFsvolWriteCachedDeferred, Irp, 0, WriteLength, + 0 != RequestWorkItem); + + return STATUS_PENDING; + } + + /* if we are unable to defer we will go ahead and (try to) service the IRP now! */ + } + + return STATUS_INVALID_DEVICE_REQUEST; +} + +static VOID FspFsvolWriteCachedDeferred(PVOID Context1, PVOID Context2) +{ + FspWqPostIrpWorkItem(Context1); +} + +static NTSTATUS FspFsvolWriteNonCached( + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); @@ -30,7 +136,13 @@ NTSTATUS FspFsvolWriteComplete( { FSP_ENTER_IOC(PAGED_CODE()); - FSP_LEAVE_IOC("%s", ""); + FSP_LEAVE_IOC( + "FileObject=%p, UserBuffer=%p, MdlAddress=%p, " + "Key=%#lx, ByteOffset=%#lx:%#lx, Length=%ld", + IrpSp->FileObject, Irp->UserBuffer, Irp->MdlAddress, + IrpSp->Parameters.Write.Key, + IrpSp->Parameters.Write.ByteOffset.HighPart, IrpSp->Parameters.Write.ByteOffset.LowPart, + IrpSp->Parameters.Write.Length); } NTSTATUS FspWrite( @@ -46,5 +158,11 @@ NTSTATUS FspWrite( FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); } - FSP_LEAVE_MJ("%s", ""); + FSP_LEAVE_MJ( + "FileObject=%p, UserBuffer=%p, MdlAddress=%p, " + "Key=%#lx, ByteOffset=%#lx:%#lx, Length=%ld", + IrpSp->FileObject, Irp->UserBuffer, Irp->MdlAddress, + IrpSp->Parameters.Write.Key, + IrpSp->Parameters.Write.ByteOffset.HighPart, IrpSp->Parameters.Write.ByteOffset.LowPart, + IrpSp->Parameters.Write.Length); }