https://git.reactos.org/?p=reactos.git;a=commitdiff;h=38078335b9ab4c5f8e8f6…
commit 38078335b9ab4c5f8e8f6f37dba5c251de5fa02a
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat May 12 12:00:09 2018 +0200
Commit: Pierre Schweitzer <pierre(a)reactos.org>
CommitDate: Sat May 12 12:03:18 2018 +0200
[FASTFAT] Implement support for stack overflow in read operations.
Before performing a read operation, FastFAT driver will
attempt to compute whether it would run out of stack
during the operation. If so, instead of attempting the
operation in the current thread, it will post the read
request to the overflow thread.
This should help with the regressions brought in by
94ead99e0c503faa40b33b813cce296ea5c0bc0c.
CORE-14601
---
drivers/filesystems/fastfat/rw.c | 279 ++++++++++++++++++++++++++-------------
1 file changed, 187 insertions(+), 92 deletions(-)
diff --git a/drivers/filesystems/fastfat/rw.c b/drivers/filesystems/fastfat/rw.c
index 4dd59933c4..76ffff933c 100644
--- a/drivers/filesystems/fastfat/rw.c
+++ b/drivers/filesystems/fastfat/rw.c
@@ -1,9 +1,10 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
- * FILE: drivers/fs/vfat/rw.c
+ * FILE: drivers/filesystems/fastfat/rw.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby(a)yahoo.com)
+ * Pierre Schweitzer (pierre(a)reactos.org)
*
*/
@@ -23,6 +24,12 @@
*/
/* #define DEBUG_VERIFY_OFFSET_CACHING */
+/* Arbitrary, taken from MS FastFAT, should be
+ * refined given what we experience in common
+ * out of stack operations
+ */
+#define OVERFLOW_READ_THRESHHOLD 0xE00
+
/* FUNCTIONS *****************************************************************/
/*
@@ -535,6 +542,169 @@ VfatWriteFileData(
return Status;
}
+NTSTATUS
+VfatCommonRead(
+ PVFAT_IRP_CONTEXT IrpContext)
+{
+ PVFATFCB Fcb;
+ PVOID Buffer;
+ NTSTATUS Status;
+ ULONG Length = 0;
+ ULONG BytesPerSector;
+ LARGE_INTEGER ByteOffset;
+ ULONG ReturnedLength = 0;
+ BOOLEAN PagingIo, CanWait, IsVolume, NoCache;
+
+ PagingIo = BooleanFlagOn(IrpContext->Irp->Flags, IRP_PAGING_IO);
+ CanWait = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT);
+ NoCache = BooleanFlagOn(IrpContext->Irp->Flags, IRP_NOCACHE);
+ Fcb = IrpContext->FileObject->FsContext;
+ IsVolume = BooleanFlagOn(Fcb->Flags, FCB_IS_VOLUME);
+
+ ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset;
+ Length = IrpContext->Stack->Parameters.Read.Length;
+ BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;
+
+ if (!PagingIo &&
+ FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
+ {
+ if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp))
+ {
+ return STATUS_FILE_LOCK_CONFLICT;
+ }
+ }
+
+ Buffer = VfatGetUserBuffer(IrpContext->Irp, PagingIo);
+
+ if (!PagingIo && !NoCache && !IsVolume)
+ {
+ // cached read
+ Status = STATUS_SUCCESS;
+ if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
+ {
+ Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
+ Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
+ }
+
+ vfatAddToStat(IrpContext->DeviceExt, Base.UserFileReads, 1);
+ vfatAddToStat(IrpContext->DeviceExt, Base.UserFileReadBytes, Length);
+
+ _SEH2_TRY
+ {
+ if (IrpContext->FileObject->PrivateCacheMap == NULL)
+ {
+ CcInitializeCacheMap(IrpContext->FileObject,
+ (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
+ FALSE,
+ &(VfatGlobalData->CacheMgrCallbacks),
+ Fcb);
+ }
+
+ if (!CcCopyRead(IrpContext->FileObject,
+ &ByteOffset,
+ Length,
+ CanWait,
+ Buffer,
+ &IrpContext->Irp->IoStatus))
+ {
+ ASSERT(!CanWait);
+ Status = STATUS_PENDING;
+ goto ByeBye;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ goto ByeBye;
+ }
+ _SEH2_END;
+
+ if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
+ {
+ Status = IrpContext->Irp->IoStatus.Status;
+ }
+ }
+ else
+ {
+ // non cached read
+ Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
+ if (!NT_SUCCESS(Status))
+ {
+ goto ByeBye;
+ }
+
+ if (ByteOffset.QuadPart + Length > ROUND_UP_64(Fcb->RFCB.FileSize.QuadPart,
BytesPerSector))
+ {
+ Length = (ULONG)(ROUND_UP_64(Fcb->RFCB.FileSize.QuadPart, BytesPerSector)
- ByteOffset.QuadPart);
+ }
+
+ if (!IsVolume)
+ {
+ vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedReads, 1);
+ vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedReadBytes, Length);
+ }
+ else
+ {
+ vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataReads, 1);
+ vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataReadBytes, Length);
+ }
+
+ Status = VfatReadFileData(IrpContext, Length, ByteOffset, &ReturnedLength);
+ if (NT_SUCCESS(Status))
+ {
+ IrpContext->Irp->IoStatus.Information = ReturnedLength;
+ }
+ }
+
+ByeBye:
+ return Status;
+}
+
+VOID
+NTAPI
+VfatStackOverflowRead(
+ PVOID Context,
+ IN PKEVENT Event)
+{
+ PVFAT_IRP_CONTEXT IrpContext;
+
+ IrpContext = Context;
+ /* In a separate thread, we can wait and resources got locked */
+ SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT);
+
+ /* Perform the read operation */
+ DPRINT1("Performing posted read\n");
+ VfatCommonRead(IrpContext);
+
+ KeSetEvent(Event, 0, FALSE);
+}
+
+VOID
+VfatPostRead(
+ PVFAT_IRP_CONTEXT IrpContext,
+ PERESOURCE Lock,
+ BOOLEAN PagingIo)
+{
+ KEVENT Event;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ ExAcquireResourceSharedLite(Lock, TRUE);
+
+ /* If paging IO, call the non failing but blocking routine */
+ if (PagingIo)
+ {
+ FsRtlPostPagingFileStackOverflow(IrpContext, &Event, VfatStackOverflowRead);
+ }
+ else
+ {
+ FsRtlPostStackOverflow(IrpContext, &Event, VfatStackOverflowRead);
+ }
+
+ /* Wait till it's done */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+}
+
NTSTATUS
VfatRead(
PVFAT_IRP_CONTEXT IrpContext)
@@ -542,10 +712,8 @@ VfatRead(
NTSTATUS Status;
PVFATFCB Fcb;
ULONG Length = 0;
- ULONG ReturnedLength = 0;
PERESOURCE Resource = NULL;
LARGE_INTEGER ByteOffset;
- PVOID Buffer;
ULONG BytesPerSector;
BOOLEAN PagingIo, CanWait, IsVolume, NoCache;
@@ -644,105 +812,32 @@ VfatRead(
Resource = &Fcb->MainResource;
}
- if (!ExAcquireResourceSharedLite(Resource, CanWait))
- {
- Resource = NULL;
- Status = STATUS_PENDING;
- goto ByeBye;
- }
-
- if (!PagingIo &&
- FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
- {
- if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp))
- {
- Status = STATUS_FILE_LOCK_CONFLICT;
- goto ByeBye;
- }
- }
-
- Buffer = VfatGetUserBuffer(IrpContext->Irp, PagingIo);
-
- if (!PagingIo && !NoCache && !IsVolume)
- {
- // cached read
- Status = STATUS_SUCCESS;
- if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
- {
- Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart;
- Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS;
- }
-
- vfatAddToStat(IrpContext->DeviceExt, Base.UserFileReads, 1);
- vfatAddToStat(IrpContext->DeviceExt, Base.UserFileReadBytes, Length);
-
- _SEH2_TRY
- {
- if (IrpContext->FileObject->PrivateCacheMap == NULL)
- {
- CcInitializeCacheMap(IrpContext->FileObject,
- (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
- FALSE,
- &(VfatGlobalData->CacheMgrCallbacks),
- Fcb);
- }
-
- if (!CcCopyRead(IrpContext->FileObject,
- &ByteOffset,
- Length,
- CanWait,
- Buffer,
- &IrpContext->Irp->IoStatus))
- {
- ASSERT(!CanWait);
- Status = STATUS_PENDING;
- goto ByeBye;
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- goto ByeBye;
- }
- _SEH2_END;
-
- if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status))
- {
- Status = IrpContext->Irp->IoStatus.Status;
- }
- }
- else
+ /* Are we out of stack for the rest of the operation? */
+ if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD)
{
- // non cached read
+ /* Lock the buffer */
Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
if (!NT_SUCCESS(Status))
{
- goto ByeBye;
+ return Status;
}
- if (ByteOffset.QuadPart + Length > ROUND_UP_64(Fcb->RFCB.FileSize.QuadPart,
BytesPerSector))
- {
- Length = (ULONG)(ROUND_UP_64(Fcb->RFCB.FileSize.QuadPart, BytesPerSector)
- ByteOffset.QuadPart);
- }
+ /* And post the read to the overflow thread */
+ VfatPostRead(IrpContext, Resource, PagingIo);
- if (!IsVolume)
- {
- vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedReads, 1);
- vfatAddToStat(IrpContext->DeviceExt, Fat.NonCachedReadBytes, Length);
- }
- else
- {
- vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataReads, 1);
- vfatAddToStat(IrpContext->DeviceExt, Base.MetaDataReadBytes, Length);
- }
+ /* Return the appropriate status */
+ return IrpContext->Irp->IoStatus.Status;
+ }
- Status = VfatReadFileData(IrpContext, Length, ByteOffset, &ReturnedLength);
- if (NT_SUCCESS(Status))
- {
- IrpContext->Irp->IoStatus.Information = ReturnedLength;
- }
+ if (!ExAcquireResourceSharedLite(Resource, CanWait))
+ {
+ Resource = NULL;
+ Status = STATUS_PENDING;
+ goto ByeBye;
}
+ Status = VfatCommonRead(IrpContext);
+
ByeBye:
if (Resource)
{