mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
[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
94ead99e0c
.
CORE-14601
This commit is contained in:
parent
0ce31759d0
commit
38078335b9
1 changed files with 189 additions and 94 deletions
|
@ -1,9 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
* FILE: drivers/fs/vfat/rw.c
|
* FILE: drivers/filesystems/fastfat/rw.c
|
||||||
* PURPOSE: VFAT Filesystem
|
* PURPOSE: VFAT Filesystem
|
||||||
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
|
||||||
|
* Pierre Schweitzer (pierre@reactos.org)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -23,6 +24,12 @@
|
||||||
*/
|
*/
|
||||||
/* #define DEBUG_VERIFY_OFFSET_CACHING */
|
/* #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 *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -535,6 +542,169 @@ VfatWriteFileData(
|
||||||
return Status;
|
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
|
NTSTATUS
|
||||||
VfatRead(
|
VfatRead(
|
||||||
PVFAT_IRP_CONTEXT IrpContext)
|
PVFAT_IRP_CONTEXT IrpContext)
|
||||||
|
@ -542,10 +712,8 @@ VfatRead(
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PVFATFCB Fcb;
|
PVFATFCB Fcb;
|
||||||
ULONG Length = 0;
|
ULONG Length = 0;
|
||||||
ULONG ReturnedLength = 0;
|
|
||||||
PERESOURCE Resource = NULL;
|
PERESOURCE Resource = NULL;
|
||||||
LARGE_INTEGER ByteOffset;
|
LARGE_INTEGER ByteOffset;
|
||||||
PVOID Buffer;
|
|
||||||
ULONG BytesPerSector;
|
ULONG BytesPerSector;
|
||||||
BOOLEAN PagingIo, CanWait, IsVolume, NoCache;
|
BOOLEAN PagingIo, CanWait, IsVolume, NoCache;
|
||||||
|
|
||||||
|
@ -644,6 +812,23 @@ VfatRead(
|
||||||
Resource = &Fcb->MainResource;
|
Resource = &Fcb->MainResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Are we out of stack for the rest of the operation? */
|
||||||
|
if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD)
|
||||||
|
{
|
||||||
|
/* Lock the buffer */
|
||||||
|
Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And post the read to the overflow thread */
|
||||||
|
VfatPostRead(IrpContext, Resource, PagingIo);
|
||||||
|
|
||||||
|
/* Return the appropriate status */
|
||||||
|
return IrpContext->Irp->IoStatus.Status;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ExAcquireResourceSharedLite(Resource, CanWait))
|
if (!ExAcquireResourceSharedLite(Resource, CanWait))
|
||||||
{
|
{
|
||||||
Resource = NULL;
|
Resource = NULL;
|
||||||
|
@ -651,97 +836,7 @@ VfatRead(
|
||||||
goto ByeBye;
|
goto ByeBye;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PagingIo &&
|
Status = VfatCommonRead(IrpContext);
|
||||||
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
|
|
||||||
{
|
|
||||||
// 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:
|
ByeBye:
|
||||||
if (Resource)
|
if (Resource)
|
||||||
|
|
Loading…
Reference in a new issue