📄 read.c
字号:
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
Read.c
Abstract:
This module implements the File Read routine for Read called by the
dispatch driver.
--*/
#include "FatProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (FAT_BUG_CHECK_READ)
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_READ)
//
// Define stack overflow read threshhold. For the x86 we'll use a smaller
// threshold than for a risc platform.
//
// Empirically, the limit is a result of the (large) amount of stack
// neccesary to throw an exception.
//
#if defined(_M_IX86)
#define OVERFLOW_READ_THRESHHOLD (0xE00)
#else
#define OVERFLOW_READ_THRESHHOLD (0x1000)
#endif // defined(_M_IX86)
//
// The following procedures handles read stack overflow operations.
//
VOID
FatStackOverflowRead (
IN PVOID Context,
IN PKEVENT Event
);
NTSTATUS
FatPostStackOverflowRead (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PFCB Fcb
);
VOID
FatOverflowPagingFileRead (
IN PVOID Context,
IN PKEVENT Event
);
//
// VOID
// SafeZeroMemory (
// IN PUCHAR At,
// IN ULONG ByteCount
// );
//
//
// This macro just puts a nice little try-except around RtlZeroMemory
//
#define SafeZeroMemory(AT,BYTE_COUNT) { \
try { \
RtlZeroMemory((AT), (BYTE_COUNT)); \
} except(EXCEPTION_EXECUTE_HANDLER) { \
FatRaiseStatus( IrpContext, STATUS_INVALID_USER_BUFFER ); \
} \
}
//
// Macro to increment appropriate performance counters.
//
#define CollectReadStats(VCB,OPEN_TYPE,BYTE_COUNT) { \
PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()].Common; \
if (((OPEN_TYPE) == UserFileOpen)) { \
Stats->UserFileReads += 1; \
Stats->UserFileReadBytes += (ULONG)(BYTE_COUNT); \
} else if (((OPEN_TYPE) == VirtualVolumeFile || ((OPEN_TYPE) == DirectoryFile))) { \
Stats->MetaDataReads += 1; \
Stats->MetaDataReadBytes += (ULONG)(BYTE_COUNT); \
} \
}
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatStackOverflowRead)
#pragma alloc_text(PAGE, FatPostStackOverflowRead)
#pragma alloc_text(PAGE, FatCommonRead)
#endif
NTSTATUS
FatFsdRead (
IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This is the driver entry to the common read routine for NtReadFile calls.
For synchronous requests, the CommonRead is called with Wait == TRUE,
which means the request will always be completed in the current thread,
and never passed to the Fsp. If it is not a synchronous request,
CommonRead is called with Wait == FALSE, which means the request
will be passed to the Fsp only if there is a need to block.
Arguments:
VolumeDeviceObject - Supplies the volume device object where the
file being Read exists
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The FSD status for the IRP
--*/
{
PFCB Fcb = NULL;
NTSTATUS Status;
PIRP_CONTEXT IrpContext = NULL;
BOOLEAN TopLevel;
DebugTrace(+1, Dbg, "FatFsdRead\n", 0);
//
// Call the common Read routine, with blocking allowed if synchronous
//
FsRtlEnterFileSystem();
//
// We are first going to do a quick check for paging file IO. Since this
// is a fast path, we must replicate the check for the fsdo.
//
if (!FatDeviceIsFatFsdo( IoGetCurrentIrpStackLocation(Irp)->DeviceObject)) {
Fcb = (PFCB)(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext);
if ((NodeType(Fcb) == FAT_NTC_FCB) &&
FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) {
//
// Do the usual STATUS_PENDING things.
//
IoMarkIrpPending( Irp );
//
// If there is not enough stack to do this read, then post this
// read to the overflow queue.
//
if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
KEVENT Event;
PAGING_FILE_OVERFLOW_PACKET Packet;
Packet.Irp = Irp;
Packet.Fcb = Fcb;
KeInitializeEvent( &Event, NotificationEvent, FALSE );
FsRtlPostPagingFileStackOverflow( &Packet, &Event, FatOverflowPagingFileRead );
//
// And wait for the worker thread to complete the item
//
(VOID) KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
} else {
//
// Perform the actual IO, it will be completed when the io finishes.
//
FatPagingFileIo( Irp, Fcb );
}
FsRtlExitFileSystem();
return STATUS_PENDING;
}
}
try {
TopLevel = FatIsIrpTopLevel( Irp );
IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ) );
//
// If this is an Mdl complete request, don't go through
// common read.
//
if ( FlagOn(IrpContext->MinorFunction, IRP_MN_COMPLETE) ) {
DebugTrace(0, Dbg, "Calling FatCompleteMdl\n", 0 );
try_return( Status = FatCompleteMdl( IrpContext, Irp ));
}
//
// Check if we have enough stack space to process this request. If there
// isn't enough then we will pass the request off to the stack overflow thread.
//
if (IoGetRemainingStackSize() < OVERFLOW_READ_THRESHHOLD) {
DebugTrace(0, Dbg, "Passing StackOverflowRead off\n", 0 );
try_return( Status = FatPostStackOverflowRead( IrpContext, Irp, Fcb ) );
}
Status = FatCommonRead( IrpContext, Irp );
try_exit: NOTHING;
} except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
//
// We had some trouble trying to perform the requested
// operation, so we'll abort the I/O request with
// the error status that we get back from the
// execption code
//
Status = FatProcessException( IrpContext, Irp, GetExceptionCode() );
}
if (TopLevel) { IoSetTopLevelIrp( NULL ); }
FsRtlExitFileSystem();
//
// And return to our caller
//
DebugTrace(-1, Dbg, "FatFsdRead -> %08lx\n", Status);
UNREFERENCED_PARAMETER( VolumeDeviceObject );
return Status;
}
//
// Internal support routine
//
NTSTATUS
FatPostStackOverflowRead (
IN PIRP_CONTEXT IrpContext,
IN PIRP Irp,
IN PFCB Fcb
)
/*++
Routine Description:
This routine posts a read request that could not be processed by
the fsp thread because of stack overflow potential.
Arguments:
Irp - Supplies the request to process.
Fcb - Supplies the file.
Return Value:
STATUS_PENDING.
--*/
{
KEVENT Event;
PERESOURCE Resource;
PVCB Vcb;
DebugTrace(0, Dbg, "Getting too close to stack limit pass request to Fsp\n", 0 );
//
// Initialize an event and get shared on the resource we will
// be later using the common read.
//
KeInitializeEvent( &Event, NotificationEvent, FALSE );
//
// Preacquire the resource the read path will require so we know the
// worker thread can proceed without waiting.
//
if (FlagOn(Irp->Flags, IRP_PAGING_IO) && (Fcb->Header.PagingIoResource != NULL)) {
Resource = Fcb->Header.PagingIoResource;
} else {
Resource = Fcb->Header.Resource;
}
//
// If there are no resources assodicated with the file (case: the virtual
// volume file), it is OK. No resources will be acquired on the other side
// as well.
//
if (Resource) {
ExAcquireResourceSharedLite( Resource, TRUE );
}
if (NodeType( Fcb ) == FAT_NTC_VCB) {
Vcb = (PVCB) Fcb;
} else {
Vcb = Fcb->Vcb;
}
try {
//
// Make the Irp just like a regular post request and
// then send the Irp to the special overflow thread.
// After the post we will wait for the stack overflow
// read routine to set the event that indicates we can
// now release the scb resource and return.
//
FatPrePostIrp( IrpContext, Irp );
//
// If this read is the result of a verify, we have to
// tell the overflow read routne to temporarily
// hijack the Vcb->VerifyThread field so that reads
// can go through.
//
if (Vcb->VerifyThread == KeGetCurrentThread()) {
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
}
FsRtlPostStackOverflow( IrpContext, &Event, FatStackOverflowRead );
//
// And wait for the worker thread to complete the item
//
KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
} finally {
if (Resource) {
ExReleaseResourceLite( Resource );
}
}
return STATUS_PENDING;
}
//
// Internal support routine
//
VOID
FatStackOverflowRead (
IN PVOID Context,
IN PKEVENT Event
)
/*++
Routine Description:
This routine processes a read request that could not be processed by
the fsp thread because of stack overflow potential.
Arguments:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -