From 12463043e4b4fe24ea4e3c5edba9ef4ecbee784d Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 15 Mar 2016 23:27:31 -0700 Subject: [PATCH] sys: FspFsvolWriteCached: update file size prior to a cached write to ensure that the user-mode file system knows the correct file size --- src/sys/driver.h | 2 ++ src/sys/util.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ src/sys/write.c | 42 +++++++++++-------------------- 3 files changed, 81 insertions(+), 28 deletions(-) diff --git a/src/sys/driver.h b/src/sys/driver.h index a74d9087..9789fffc 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -389,6 +389,8 @@ 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 FspSendSetInformationIrp(PFILE_OBJECT FileObject, + FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length); NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl); NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress); diff --git a/src/sys/util.c b/src/sys/util.c index d5718f6a..f357034d 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -9,6 +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 FspSendSetInformationIrp(PFILE_OBJECT FileObject, + FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length); +static NTSTATUS FspSendSetInformationIrpCompletion( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0); NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl); NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress); @@ -45,6 +49,7 @@ VOID FspSafeMdlDelete(FSP_SAFE_MDL *SafeMdl); #pragma alloc_text(PAGE, FspUnicodePathIsValid) #pragma alloc_text(PAGE, FspUnicodePathSuffix) #pragma alloc_text(PAGE, FspCreateGuid) +#pragma alloc_text(PAGE, FspSendSetInformationIrp) #pragma alloc_text(PAGE, FspLockUserBuffer) #pragma alloc_text(PAGE, FspMapLockedPagesInUserMode) #pragma alloc_text(PAGE, FspCcInitializeCacheMap) @@ -185,6 +190,66 @@ NTSTATUS FspCreateGuid(GUID *Guid) return Result; } +typedef struct +{ + IO_STATUS_BLOCK IoStatus; + KEVENT Event; +} FSP_SEND_SET_INFORMATION_IRP_CONTEXT; + +NTSTATUS FspSendSetInformationIrp(PFILE_OBJECT FileObject, + FILE_INFORMATION_CLASS FileInformationClass, PVOID FileInformation, ULONG Length) +{ + PAGED_CODE(); + + ASSERT( + FileAllocationInformation == FileInformationClass || + FileEndOfFileInformation == FileInformationClass); + + NTSTATUS Result; + PDEVICE_OBJECT DeviceObject; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + FSP_SEND_SET_INFORMATION_IRP_CONTEXT Context; + + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (0 == Irp) + return STATUS_INSUFFICIENT_RESOURCES; + + IrpSp = IoGetNextIrpStackLocation(Irp); + Irp->RequestorMode = KernelMode; + Irp->AssociatedIrp.SystemBuffer = FileInformation; + IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION; + IrpSp->FileObject = FileObject; + IrpSp->Parameters.SetFile.FileInformationClass = FileInformationClass; + IrpSp->Parameters.SetFile.Length = FileInformationClass; + + IoSetCompletionRoutine(Irp, FspSendSetInformationIrpCompletion, &Context, TRUE, TRUE, TRUE); + + KeInitializeEvent(&Context.Event, NotificationEvent, FALSE); + Result = IoCallDriver(DeviceObject, Irp); + if (STATUS_PENDING == Result) + KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, 0); + + return NT_SUCCESS(Result) ? Context.IoStatus.Status : Result; +} + +static NTSTATUS FspSendSetInformationIrpCompletion( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context0) +{ + // !PAGED_CODE(); + + FSP_SEND_SET_INFORMATION_IRP_CONTEXT *Context = Context0; + + Context->IoStatus = Irp->IoStatus; + KeSetEvent(&Context->Event, 1, FALSE); + + IoFreeIrp(Irp); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl) { diff --git a/src/sys/write.c b/src/sys/write.c index 1a7eb7f2..2d728985 100644 --- a/src/sys/write.c +++ b/src/sys/write.c @@ -106,7 +106,7 @@ static NTSTATUS FspFsvolWriteCached( BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); FSP_FSCTL_FILE_INFO FileInfo; CC_FILE_SIZES FileSizes; - UINT64 OriginalFileSize; + FILE_END_OF_FILE_INFORMATION EndOfFileInformation; UINT64 WriteEndOffset; BOOLEAN ExtendingFile; BOOLEAN Success; @@ -133,26 +133,18 @@ static NTSTATUS FspFsvolWriteCached( if (!Success) return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0); - /* compute new file size and allocation size */ + /* compute new file size */ ASSERT(FspTimeoutInfinity32 == FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout); FspFileNodeGetFileInfo(FileNode, &FileInfo); - OriginalFileSize = FileInfo.FileSize; WriteEndOffset = WriteToEndOfFile ? FileInfo.FileSize + WriteLength : WriteOffset.QuadPart + WriteLength; ExtendingFile = FileInfo.FileSize < WriteEndOffset; - if (ExtendingFile) + if (ExtendingFile && !CanWait) { - FileInfo.FileSize = WriteEndOffset; - if (FileInfo.FileSize > FileInfo.AllocationSize) - { - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = - FspFsvolDeviceExtension(FsvolDeviceObject); - UINT64 AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize * - FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit; - FileInfo.AllocationSize = (FileInfo.FileSize + AllocationUnit - 1) - / AllocationUnit * AllocationUnit; - } + /* need CanWait==TRUE for FspSendSetInformationIrp */ + FspFileNodeRelease(FileNode, Main); + return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0); } /* initialize cache if not already initialized! */ @@ -170,14 +162,15 @@ static NTSTATUS FspFsvolWriteCached( return Result; } } - else if (ExtendingFile) - { - FileSizes.AllocationSize.QuadPart = FileInfo.AllocationSize; - FileSizes.FileSize.QuadPart = FileInfo.FileSize; - FileSizes.ValidDataLength.QuadPart = MAXLONGLONG; - /* file is being extended */ - Result = FspCcSetFileSizes(FileObject, &FileSizes); + /* are we extending the file? */ + if (ExtendingFile) + { + ASSERT(CanWait); + + EndOfFileInformation.EndOfFile.QuadPart = WriteEndOffset; + Result = FspSendSetInformationIrp(FileObject, FileEndOfFileInformation, + &EndOfFileInformation, sizeof EndOfFileInformation); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Main); @@ -223,18 +216,11 @@ static NTSTATUS FspFsvolWriteCached( if (SynchronousIo) FileObject->CurrentByteOffset.QuadPart = WriteEndOffset; - if (ExtendingFile) - FspFileNodeSetFileInfo(FileNode, 0, &FileInfo); - FspFileNodeRelease(FileNode, Main); return STATUS_SUCCESS; cleanup: - /* pull back the cache file size if we extended it */ - if (ExtendingFile) - CcGetFileSizePointer(FileObject)->QuadPart = OriginalFileSize; - FspFileNodeRelease(FileNode, Main); if (STATUS_PENDING == Result)