From 12cec5dc2261b5da7b6fb07164b4968cd3d0f0b7 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 20 Jan 2016 15:42:33 -0800 Subject: [PATCH] sys: FspFsvolCreateTryFlushImage --- inc/winfsp/fsctl.h | 2 +- src/sys/create.c | 133 +++++++++++++++++++++++++++++++++++++++++---- src/sys/driver.h | 21 +++++++ src/sys/iop.c | 10 +--- src/sys/volume.c | 4 +- 5 files changed, 149 insertions(+), 21 deletions(-) diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 740d66a4..b2b0df6a 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -48,7 +48,7 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid = #pragma warning(disable:4200) /* zero-sized array in struct/union */ enum { - FspFsctlTransactUnknownKind = 0, + FspFsctlTransactReservedKind = 0, FspFsctlTransactCreateKind, FspFsctlTransactOverwriteKind, FspFsctlTransactCleanupKind, diff --git a/src/sys/create.c b/src/sys/create.c index 0893b9f6..9f1824e8 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -15,7 +15,10 @@ static NTSTATUS FspFsvolCreate( FSP_IOPREP_DISPATCH FspFsvolCreatePrepare; FSP_IOCMPL_DISPATCH FspFsvolCreateComplete; static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc); +static NTSTATUS FspFsvolCreateTryFlushImage(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request, + FSP_FILE_NODE *FileNode, FSP_FILE_DESC *FileDesc, PFILE_OBJECT FileObject); static FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini; +static FSP_IOP_REQUEST_FINI FspFsvolCreateReservedRequestFini; static FSP_IOP_REQUEST_FINI FspFsvolCreateOverwriteRequestFini; FSP_DRIVER_DISPATCH FspCreate; @@ -26,7 +29,9 @@ FSP_DRIVER_DISPATCH FspCreate; #pragma alloc_text(PAGE, FspFsvolCreatePrepare) #pragma alloc_text(PAGE, FspFsvolCreateComplete) #pragma alloc_text(PAGE, FspFsvolCreatePostClose) +#pragma alloc_text(PAGE, FspFsvolCreateTryFlushImage) #pragma alloc_text(PAGE, FspFsvolCreateRequestFini) +#pragma alloc_text(PAGE, FspFsvolCreateReservedRequestFini) #pragma alloc_text(PAGE, FspFsvolCreateOverwriteRequestFini) #pragma alloc_text(PAGE, FspCreate) #endif @@ -41,7 +46,7 @@ enum RequestAccessToken = 1, RequestProcess = 2, - /* OverwriteRequest */ + /* Reserved/OverwriteRequest */ //RequestFileDesc = 0, RequestFileObject = 1, RequestState = 2, @@ -347,7 +352,37 @@ NTSTATUS FspFsvolCreatePrepare( FSP_FILE_DESC *FileDesc; PFILE_OBJECT FileObject; - if (FspFsctlTransactCreateKind == Request->Kind) + if (FspFsctlTransactReservedKind == Request->Kind) + { + /* + * This branch is not taken during IRP preparation, but rather during IRP completion + * when FlushImageSection needs to be retried. + */ + FileDesc = FspIopRequestContext(Request, RequestFileDesc); + FileNode = FileDesc->FileNode; + FileObject = FspIopRequestContext(Request, RequestFileObject); + + Result = FspFsvolCreateTryFlushImage(Irp, Request, FileNode, FileDesc, FileObject); + if (STATUS_PENDING == Result) + return Result; + else + { + if (NT_SUCCESS(Result)) + { + /* SUCCESS! */ + FspIopRequestContext(Request, RequestFileDesc) = 0; + Irp->IoStatus.Information = FILE_OPENED; + Result = STATUS_SUCCESS; + } + + DEBUGLOGIRP(Irp, Result); + + FspIopCompleteIrp(Irp, Result); + + return FSP_STATUS_COMPLETED; + } + } + else if (FspFsctlTransactCreateKind == Request->Kind) { SecuritySubjectContext = &IrpSp->Parameters.Create.SecurityContext-> AccessState->SubjectSecurityContext; @@ -558,15 +593,9 @@ VOID FspFsvolCreateComplete( if (FlagOn(Response->Rsp.Create.Opened.GrantedAccess, FILE_WRITE_DATA) || DeleteOnClose) { - if (!MmFlushImageSection(&FileNode->NonPaged->SectionObjectPointers, - MmFlushForWrite)) - { - FspFsvolCreatePostClose(FileDesc); - FspFileNodeClose(FileNode, FileObject, 0); - - Result = DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; + Result = FspFsvolCreateTryFlushImage(Irp, 0, FileNode, FileDesc, FileObject); + if (STATUS_PENDING == Result || !NT_SUCCESS(Result)) FSP_RETURN(); - } } /* SUCCESS! */ @@ -690,6 +719,70 @@ static VOID FspFsvolCreatePostClose(FSP_FILE_DESC *FileDesc) */ } +static NTSTATUS FspFsvolCreateTryFlushImage(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request, + FSP_FILE_NODE *FileNode, FSP_FILE_DESC *FileDesc, PFILE_OBJECT FileObject) +{ + PAGED_CODE(); + + ASSERT(0 == Request || FspFsctlTransactReservedKind == Request->Kind); + + BOOLEAN Success; + + Success = FspFileNodeTryAcquireExclusive(FileNode, Main); + if (!Success) + { + /* repost the IRP to retry later */ + NTSTATUS Result; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = + FspFsvolDeviceExtension(IrpSp->DeviceObject); + + if (0 == Request) + { + /* delete the old request */ + Request = FspIrpRequest(Irp); + FspIrpRequest(Irp) = 0; + FspIopRequestContext(Request, RequestFileDesc) = 0; + /* disassociate the FileDesc from the old Request as we want to keep it around! */ + FspIopDeleteRequest(Request); + + /* create the special Reserved request */ + FspIopCreateRequestFunnel(Irp, 0, 0, + FspFsvolCreateReservedRequestFini, TRUE, + &Request); + + /* associate the FileDesc and FileObject with the Reserved request */ + FspIopRequestContext(Request, RequestFileDesc) = FileDesc; + FspIopRequestContext(Request, RequestFileObject) = FileObject; + + Request->Kind = FspFsctlTransactReservedKind; + } + + FspIoqPostIrpBestEffort(FsvolDeviceExtension->Ioq, Irp, &Result); + + return Result; + } + + Success = MmFlushImageSection(&FileNode->NonPaged->SectionObjectPointers, + MmFlushForWrite); + FspFileNodeRelease(FileNode, Main); + if (!Success) + { + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + BOOLEAN DeleteOnClose = BooleanFlagOn(IrpSp->Parameters.Create.Options, FILE_DELETE_ON_CLOSE); + + if (0 == Request) + { + FspFsvolCreatePostClose(FileDesc); + FspFileNodeClose(FileNode, FileObject, 0); + } + + return DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; + } + + return STATUS_SUCCESS; +} + static VOID FspFsvolCreateRequestFini(PVOID Context[3]) { PAGED_CODE(); @@ -731,6 +824,26 @@ static VOID FspFsvolCreateRequestFini(PVOID Context[3]) Context[RequestFileDesc] = Context[RequestAccessToken] = Context[RequestProcess] = 0; } +static VOID FspFsvolCreateReservedRequestFini(PVOID Context[3]) +{ + PAGED_CODE(); + + FSP_FILE_DESC *FileDesc = Context[RequestFileDesc]; + PFILE_OBJECT FileObject = Context[RequestFileObject]; + + if (0 != FileDesc) + { + ASSERT(0 != FileObject); + + FspFsvolCreatePostClose(FileDesc); + FspFileNodeClose(FileDesc->FileNode, FileObject, 0); + FspFileNodeDereference(FileDesc->FileNode); + FspFileDescDelete(FileDesc); + } + + Context[RequestFileDesc] = Context[RequestFileObject] = 0; +} + static VOID FspFsvolCreateOverwriteRequestFini(PVOID Context[3]) { PAGED_CODE(); diff --git a/src/sys/driver.h b/src/sys/driver.h index 8c1b4fc9..e8f7c89d 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -29,6 +29,7 @@ #define FSP_STATUS_PRIVATE_BIT (0x20000000) #define FSP_STATUS_IOQ_POST (FSP_STATUS_PRIVATE_BIT | 0x0000) #define FSP_STATUS_IOQ_POST_BEST_EFFORT (FSP_STATUS_PRIVATE_BIT | 0x0001) +#define FSP_STATUS_COMPLETED (FSP_STATUS_PRIVATE_BIT | 0x0002) /* misc macros */ #define FSP_ALLOC_INTERNAL_TAG 'IpsF' @@ -43,6 +44,13 @@ #define DEBUGLOG(fmt, ...) ((void)0) #endif +/* DEBUGLOGIRP */ +#if DBG +#define DEBUGLOGIRP(Irp, Result) FspDebugLogIrp(Irp, Result) +#else +#define DEBUGLOGIRP(Irp, Result) ((void)0) +#endif + /* DEBUGBREAK */ #if DBG extern __declspec(selectany) int fsp_bp = 1; @@ -590,6 +598,19 @@ const char *NtStatusSym(NTSTATUS Status); const char *IrpMajorFunctionSym(UCHAR MajorFunction); const char *IrpMinorFunctionSym(UCHAR MajorFunction, UCHAR MinorFunction); const char *IoctlCodeSym(ULONG ControlCode); +static inline +VOID FspDebugLogIrp(PIRP Irp, NTSTATUS Result) +{ + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + DEBUGLOG("IRP=%p, %s%c, %s%s, IoStatus=%s[%lld]", + Irp, + (const char *)&FspDeviceExtension(IrpSp->DeviceObject)->Kind, + Irp->RequestorMode == KernelMode ? 'K' : 'U', + IrpMajorFunctionSym(IrpSp->MajorFunction), + IrpMinorFunctionSym(IrpSp->MajorFunction, IrpSp->MinorFunction), + NtStatusSym(Result), + (LONGLONG)Irp->IoStatus.Information); +} #endif /* extern */ diff --git a/src/sys/iop.c b/src/sys/iop.c index 04a3f869..f98f7f63 100644 --- a/src/sys/iop.c +++ b/src/sys/iop.c @@ -238,15 +238,7 @@ VOID FspIopCompleteCanceledIrp(PIRP Irp) { PAGED_CODE(); -#if DBG - PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - DEBUGLOG("IRP=%p, %s%c, %s%s", - Irp, - (const char *)&FspDeviceExtension(IrpSp->DeviceObject)->Kind, - Irp->RequestorMode == KernelMode ? 'K' : 'U', - IrpMajorFunctionSym(IrpSp->MajorFunction), - IrpMinorFunctionSym(IrpSp->MajorFunction, IrpSp->MinorFunction)); -#endif + DEBUGLOGIRP(Irp, STATUS_CANCELLED); FspIopCompleteIrpEx(Irp, STATUS_CANCELLED, TRUE); } diff --git a/src/sys/volume.c b/src/sys/volume.c index 81f5dcc7..f01006f5 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -565,7 +565,9 @@ NTSTATUS FspVolumeTransact( PendingIrpRequest = FspIrpRequest(PendingIrp); Result = FspIopDispatchPrepare(PendingIrp, PendingIrpRequest); - if (STATUS_PENDING == Result) + if (FSP_STATUS_COMPLETED == Result) + ; + else if (STATUS_PENDING == Result) { /* * The IRP has been reposted to our Ioq. Remember the first such IRP,