📄 deviosup.c
字号:
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
DevIoSup.c
Abstract:
This module implements the low lever disk read/write support for Fat.
--*/
#include "FatProcs.h"
//
// The Bug check file id for this module
//
#define BugCheckFileId (FAT_BUG_CHECK_DEVIOSUP)
//
// Local debug trace level
//
#define Dbg (DEBUG_TRACE_DEVIOSUP)
#define CollectDiskIoStats(VCB,FUNCTION,IS_USER_IO,COUNT) { \
PFILESYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber()].Common; \
if (IS_USER_IO) { \
if ((FUNCTION) == IRP_MJ_WRITE) { \
Stats->UserDiskWrites += (COUNT); \
} else { \
Stats->UserDiskReads += (COUNT); \
} \
} else { \
if ((FUNCTION) == IRP_MJ_WRITE) { \
Stats->MetaDataDiskWrites += (COUNT); \
} else { \
Stats->MetaDataDiskReads += (COUNT); \
} \
} \
}
//
// Completion Routine declarations
//
NTSTATUS
FatMultiSyncCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
);
NTSTATUS
FatMultiAsyncCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
);
NTSTATUS
FatSpecialSyncCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
);
NTSTATUS
FatSingleSyncCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
);
NTSTATUS
FatSingleAsyncCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
);
NTSTATUS
FatPagingFileCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID MasterIrp
);
NTSTATUS
FatPagingFileCompletionRoutineCatch (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
);
VOID
FatSingleNonAlignedSync (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
IN PUCHAR Buffer,
IN LBO Lbo,
IN ULONG ByteCount,
IN PIRP Irp
);
//
// The following macro decides whether to send a request directly to
// the device driver, or to other routines. It was meant to
// replace IoCallDriver as transparently as possible. It must only be
// called with a read or write Irp.
//
// NTSTATUS
// FatLowLevelReadWrite (
// PIRP_CONTEXT IrpContext,
// PDEVICE_OBJECT DeviceObject,
// PIRP Irp,
// PVCB Vcb
// );
//
#define FatLowLevelReadWrite(IRPCONTEXT,DO,IRP,VCB) ( \
IoCallDriver((DO),(IRP)) \
)
//
// The following macro handles completion-time zeroing of buffers.
//
#define FatDoCompletionZero( I, C ) \
if ((C)->ZeroMdl) { \
ASSERT( (C)->ZeroMdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | \
MDL_SOURCE_IS_NONPAGED_POOL));\
if (NT_SUCCESS((I)->IoStatus.Status)) { \
RtlZeroMemory( (C)->ZeroMdl->MappedSystemVa, \
(C)->ZeroMdl->ByteCount ); \
} \
IoFreeMdl((C)->ZeroMdl); \
(C)->ZeroMdl = NULL; \
}
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FatMultipleAsync)
#pragma alloc_text(PAGE, FatSingleAsync)
#pragma alloc_text(PAGE, FatSingleNonAlignedSync)
#pragma alloc_text(PAGE, FatWaitSync)
#pragma alloc_text(PAGE, FatLockUserBuffer)
#pragma alloc_text(PAGE, FatBufferUserBuffer)
#pragma alloc_text(PAGE, FatMapUserBuffer)
#pragma alloc_text(PAGE, FatNonCachedIo)
#pragma alloc_text(PAGE, FatSingleNonAlignedSync)
#pragma alloc_text(PAGE, FatNonCachedNonAlignedRead)
#endif
typedef struct FAT_PAGING_FILE_CONTEXT {
KEVENT Event;
PMDL RestoreMdl;
} FAT_PAGING_FILE_CONTEXT, *PFAT_PAGING_FILE_CONTEXT;
VOID
FatPagingFileIo (
IN PIRP Irp,
IN PFCB Fcb
)
/*++
Routine Description:
This routine performs the non-cached disk io described in its parameters.
This routine nevers blocks, and should only be used with the paging
file since no completion processing is performed.
Arguments:
Irp - Supplies the requesting Irp.
Fcb - Supplies the file to act on.
Return Value:
None.
--*/
{
//
// Declare some local variables for enumeration through the
// runs of the file.
//
VBO Vbo;
ULONG ByteCount;
PMDL Mdl;
LBO NextLbo;
VBO NextVbo;
ULONG NextByteCount;
ULONG RemainingByteCount;
BOOLEAN MustSucceed;
ULONG FirstIndex;
ULONG CurrentIndex;
ULONG LastIndex;
LBO LastLbo;
ULONG LastByteCount;
BOOLEAN MdlIsReserve = FALSE;
BOOLEAN IrpIsMaster = FALSE;
FAT_PAGING_FILE_CONTEXT Context;
LONG IrpCount;
PIRP AssocIrp;
PIO_STACK_LOCATION IrpSp;
PIO_STACK_LOCATION NextIrpSp;
ULONG BufferOffset;
PDEVICE_OBJECT DeviceObject;
DebugTrace(+1, Dbg, "FatPagingFileIo\n", 0);
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
DebugTrace( 0, Dbg, "Fcb = %08lx\n", Fcb );
ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE ));
//
// Initialize some locals.
//
BufferOffset = 0;
DeviceObject = Fcb->Vcb->TargetDeviceObject;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
Vbo = IrpSp->Parameters.Read.ByteOffset.LowPart;
ByteCount = IrpSp->Parameters.Read.Length;
MustSucceed = FatLookupMcbEntry( Fcb->Vcb, &Fcb->Mcb,
Vbo,
&NextLbo,
&NextByteCount,
&FirstIndex);
//
// If this run isn't present, something is very wrong.
//
if (!MustSucceed) {
FatBugCheck( Vbo, ByteCount, 0 );
}
//
// See if the write covers a single valid run, and if so pass
// it on.
//
if ( NextByteCount >= ByteCount ) {
DebugTrace( 0, Dbg, "Passing Irp on to Disk Driver\n", 0 );
//
// Setup the next IRP stack location for the disk driver beneath us.
//
NextIrpSp = IoGetNextIrpStackLocation( Irp );
NextIrpSp->MajorFunction = IrpSp->MajorFunction;
NextIrpSp->Parameters.Read.Length = ByteCount;
NextIrpSp->Parameters.Read.ByteOffset.QuadPart = NextLbo;
//
// Since this is Paging file IO, we'll just ignore the verify bit.
//
SetFlag( NextIrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
//
// Set up the completion routine address in our stack frame.
// This is only invoked on error or cancel, and just copies
// the error Status into master irp's iosb.
//
// If the error implies a media problem, it also enqueues a
// worker item to write out the dirty bit so that the next
// time we run we will do a autochk /r
//
IoSetCompletionRoutine( Irp,
&FatPagingFileCompletionRoutine,
Irp,
FALSE,
TRUE,
TRUE );
//
// Issue the read/write request
//
// If IoCallDriver returns an error, it has completed the Irp
// and the error will be dealt with as a normal IO error.
//
(VOID)IoCallDriver( DeviceObject, Irp );
DebugTrace(-1, Dbg, "FatPagingFileIo -> VOID\n", 0);
return;
}
//
// Find out how may runs there are.
//
MustSucceed = FatLookupMcbEntry( Fcb->Vcb, &Fcb->Mcb,
Vbo + ByteCount - 1,
&LastLbo,
&LastByteCount,
&LastIndex);
//
// If this run isn't present, something is very wrong.
//
if (!MustSucceed) {
FatBugCheck( Vbo + ByteCount - 1, 1, 0 );
}
CurrentIndex = FirstIndex;
//
// Now set up the Irp->IoStatus. It will be modified by the
// multi-completion routine in case of error or verify required.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = ByteCount;
//
// Loop while there are still byte writes to satisfy. The way we'll work this
// is to hope for the best - one associated IRP per run, which will let us be
// completely async after launching all the IO.
//
// IrpCount will indicate the remaining number of associated Irps to launch.
//
// All we have to do is make sure IrpCount doesn't hit zero before we're building
// the very last Irp. If it is positive when we're done, it means we have to
// wait for the rest of the associated Irps to come back before we complete the
// master by hand.
//
// This will keep the master from completing early.
//
Irp->AssociatedIrp.IrpCount = IrpCount = LastIndex - FirstIndex + 1;
while (CurrentIndex <= LastIndex) {
//
// Reset this for unwinding purposes
//
AssocIrp = NULL;
//
// If next run is larger than we need, "ya get what ya need".
//
if (NextByteCount > ByteCount) {
NextByteCount = ByteCount;
}
RemainingByteCount = 0;
//
// Allocate and build a partial Mdl for the request.
//
Mdl = IoAllocateMdl( (PCHAR)Irp->UserBuffer + BufferOffset,
NextByteCount,
FALSE,
FALSE,
AssocIrp );
if (Mdl == NULL) {
//
// Pick up the reserve MDL
//
KeWaitForSingleObject( &FatReserveEvent, Executive, KernelMode, FALSE, NULL );
Mdl = FatReserveMdl;
MdlIsReserve = TRUE;
//
// Trim to fit the size of the reserve MDL.
//
if (NextByteCount > FAT_RESERVE_MDL_SIZE * PAGE_SIZE) {
RemainingByteCount = NextByteCount - FAT_RESERVE_MDL_SIZE * PAGE_SIZE;
NextByteCount = FAT_RESERVE_MDL_SIZE * PAGE_SIZE;
}
}
IoBuildPartialMdl( Irp->MdlAddress,
Mdl,
(PCHAR)Irp->UserBuffer + BufferOffset,
NextByteCount );
//
// Now that we have properly bounded this piece of the transfer, it is
// time to read/write it. We can simplify life slightly by always
// re-using the master IRP for cases where we use the reserve MDL,
// since we'll always be synchronous for those and can use a single
// completion context on our local stack.
//
// We also must prevent ourselves from issuing an associated IRP that would
// complete the master UNLESS this is the very last IRP we'll issue.
//
// This logic looks a bit nasty, but is hopefully straightforward.
//
if (!MdlIsReserve &&
(IrpCount != 1 ||
(CurrentIndex == LastIndex &&
RemainingByteCount == 0))) {
AssocIrp = IoMakeAssociatedIrp( Irp, (CCHAR)(DeviceObject->StackSize + 1) );
}
if (AssocIrp == NULL) {
AssocIrp = Irp;
IrpIsMaster = TRUE;
//
// We need to drain the associated Irps so we can reliably figure out if
// the master Irp is showing a failed status, in which case we bail out
// immediately - as opposed to putting the value in the status field in
// jeopardy due to our re-use of the master Irp.
//
while (Irp->AssociatedIrp.IrpCount != IrpCount) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -