2445 lines
63 KiB
C
2445 lines
63 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
DevIoSup.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the low lever disk read/write support for Rx.
|
||
|
||
Author:
|
||
|
||
Gary Kimura [GaryKi] 22-Jan-1990
|
||
|
||
Revision History:
|
||
|
||
David Goebel [DavidGoe] 05-Oct-1990
|
||
|
||
Major changes for the new RDBSS
|
||
|
||
|
||
Tom Miller [TomM] 22-Apr-1990
|
||
|
||
Added User Buffer Locking and Mapping routines
|
||
Modified behavior of async I/O routines to use completion routines
|
||
|
||
--*/
|
||
|
||
// ----------------------joejoe-----------found-------------#include "RxProcs.h"
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// The Bug check file id for this module
|
||
//
|
||
|
||
#define BugCheckFileId (RDBSS_BUG_CHECK_DEVIOSUP)
|
||
|
||
//
|
||
// Local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_DEVIOSUP)
|
||
|
||
//
|
||
// Completion Routine declarations
|
||
//
|
||
|
||
RXSTATUS
|
||
RxMultiSyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
);
|
||
|
||
RXSTATUS
|
||
RxMultiAsyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
);
|
||
|
||
RXSTATUS
|
||
RxSingleSyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
);
|
||
|
||
RXSTATUS
|
||
RxSingleAsyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
);
|
||
|
||
RXSTATUS
|
||
RxPagingFileCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID MasterIrp
|
||
);
|
||
|
||
VOID
|
||
RxSingleNonAlignedSync (
|
||
IN PRX_CONTEXT RxContext,
|
||
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 the double space routines. It was meant to
|
||
// replace IoCallDriver as transparently as possible. It must only be
|
||
// called with a read or write Irp.
|
||
//
|
||
// RXSTATUS
|
||
// RxLowLevelReadWrite (
|
||
// PRX_CONTEXT RxContext,
|
||
// PDEVICE_OBJECT DeviceObject,
|
||
// PIRP Irp,
|
||
// PVCB Vcb
|
||
// );
|
||
//
|
||
|
||
#ifdef WE_WON_ON_APPEAL
|
||
#define RxLowLevelReadWrite(RXCONTEXT,DO,IRP,VCB) ( \
|
||
(VCB)->Dscb == NULL ? \
|
||
IoCallDriver((DO),(IRP)) : \
|
||
RxLowLevelDblsReadWrite((RXCONTEXT),(IRP),(VCB)) \
|
||
)
|
||
#else
|
||
#define RxLowLevelReadWrite(RXCONTEXT,DO,IRP,VCB) ( \
|
||
IoCallDriver((DO),(IRP)) \
|
||
)
|
||
#endif // WE_WON_ON_APPEAL
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, RxMultipleAsync)
|
||
#pragma alloc_text(PAGE, RxSingleAsync)
|
||
#pragma alloc_text(PAGE, RxSingleNonAlignedSync)
|
||
#pragma alloc_text(PAGE, RxToggleMediaEjectDisable)
|
||
#pragma alloc_text(PAGE, RxNonCachedIo)
|
||
#pragma alloc_text(PAGE, RxSingleNonAlignedSync)
|
||
#pragma alloc_text(PAGE, RxNonCachedNonAlignedRead)
|
||
#endif
|
||
|
||
|
||
VOID
|
||
RxPagingFileIo (
|
||
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;
|
||
BOOLEAN MustSucceed;
|
||
|
||
ULONG FirstIndex;
|
||
ULONG CurrentIndex;
|
||
ULONG LastIndex;
|
||
|
||
LBO LastLbo;
|
||
ULONG LastByteCount;
|
||
|
||
PIRP AssocIrp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PIO_STACK_LOCATION NextIrpSp;
|
||
ULONG BufferOffset;
|
||
PDEVICE_OBJECT DeviceObject;
|
||
|
||
DebugTrace(+1, Dbg, "RxPagingFileIo\n", 0);
|
||
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
|
||
DebugTrace( 0, Dbg, "Fcb = %08lx\n", Fcb );
|
||
|
||
//
|
||
// Initialize some locals.
|
||
//
|
||
|
||
BufferOffset = 0;
|
||
DeviceObject = Fcb->Vcb->TargetDeviceObject;
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
Vbo = IrpSp->Parameters.Read.ByteOffset.LowPart;
|
||
ByteCount = IrpSp->Parameters.Read.Length;
|
||
|
||
MustSucceed = FsRtlLookupMcbEntry( &Fcb->Mcb,
|
||
Vbo,
|
||
&NextLbo,
|
||
&NextByteCount,
|
||
&FirstIndex);
|
||
|
||
//
|
||
// If this run isn't present, something is very wrong.
|
||
//
|
||
|
||
if (!MustSucceed) {
|
||
|
||
RxBugCheck( 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.
|
||
//
|
||
|
||
if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ||
|
||
(Fcb->Vcb->VerifyThread == KeGetCurrentThread())) {
|
||
|
||
SetFlag( IrpSp->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,
|
||
&RxPagingFileCompletionRoutine,
|
||
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, "RxPagingFileIo -> VOID\n", 0);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Find out how may runs there are.
|
||
//
|
||
|
||
MustSucceed = FsRtlLookupMcbEntry( &Fcb->Mcb,
|
||
Vbo + ByteCount - 1,
|
||
&LastLbo,
|
||
&LastByteCount,
|
||
&LastIndex);
|
||
|
||
//
|
||
// If this run isn't present, something is very wrong.
|
||
//
|
||
|
||
if (!MustSucceed) {
|
||
|
||
RxBugCheck( 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 = RxStatus(SUCCESS);
|
||
Irp->IoStatus.Information = ByteCount;
|
||
|
||
//
|
||
// Loop while there are still byte writes to satisfy. If we fail to
|
||
// allocate resources the AssociatedIrp.IrpCount will be high enough
|
||
// that we can safely complete the Master Irp.
|
||
//
|
||
|
||
Irp->AssociatedIrp.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 you need".
|
||
//
|
||
|
||
if (NextByteCount > ByteCount) {
|
||
NextByteCount = ByteCount;
|
||
}
|
||
|
||
//
|
||
// Now that we have properly bounded this piece of the
|
||
// transfer, it is time to read/write it.
|
||
//
|
||
|
||
AssocIrp = IoMakeAssociatedIrp( Irp, (CCHAR)(DeviceObject->StackSize + 1) );
|
||
|
||
if (AssocIrp == NULL) {
|
||
|
||
//
|
||
// This is a rare case, so just spin until all pending Associated
|
||
// Irps complete.
|
||
//
|
||
|
||
while (Irp->AssociatedIrp.IrpCount !=
|
||
(LONG)(LastIndex - CurrentIndex + 1)) {
|
||
|
||
//
|
||
// Wait for a short time so other processing can continue.
|
||
//
|
||
|
||
KeDelayExecutionThread (KernelMode, FALSE, &Rx30Milliseconds);
|
||
}
|
||
|
||
Irp->IoStatus.Status = RxStatus(INSUFFICIENT_RESOURCES);
|
||
Irp->IoStatus.Information = 0;
|
||
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Allocate and build a partial Mdl for the request.
|
||
//
|
||
|
||
Mdl = IoAllocateMdl( (PCHAR)Irp->UserBuffer + BufferOffset,
|
||
NextByteCount,
|
||
FALSE,
|
||
FALSE,
|
||
AssocIrp );
|
||
|
||
if (Mdl == NULL) {
|
||
|
||
IoFreeIrp( AssocIrp );
|
||
|
||
//
|
||
// This is a rare case, so just spin until all pending Associated
|
||
// Irps complete.
|
||
//
|
||
|
||
while (Irp->AssociatedIrp.IrpCount !=
|
||
(LONG)(LastIndex - CurrentIndex + 1)) {
|
||
|
||
//
|
||
// Wait for a short time so other processing can continue.
|
||
//
|
||
|
||
KeDelayExecutionThread (KernelMode, FALSE, &Rx30Milliseconds);
|
||
}
|
||
|
||
Irp->IoStatus.Status = RxStatus(INSUFFICIENT_RESOURCES);
|
||
Irp->IoStatus.Information = 0;
|
||
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
|
||
|
||
return;
|
||
}
|
||
|
||
IoBuildPartialMdl( Irp->MdlAddress,
|
||
Mdl,
|
||
(PCHAR)Irp->UserBuffer + BufferOffset,
|
||
NextByteCount );
|
||
|
||
//
|
||
// Get the first IRP stack location in the associated Irp
|
||
//
|
||
|
||
IoSetNextIrpStackLocation( AssocIrp );
|
||
NextIrpSp = IoGetCurrentIrpStackLocation( AssocIrp );
|
||
|
||
//
|
||
// Setup the Stack location to describe our read.
|
||
//
|
||
|
||
NextIrpSp->MajorFunction = IrpSp->MajorFunction;
|
||
NextIrpSp->Parameters.Read.Length = NextByteCount;
|
||
NextIrpSp->Parameters.Read.ByteOffset.QuadPart = Vbo;
|
||
|
||
//
|
||
// We also need the RxDeviceObject in the Irp stack in case
|
||
// we take the failure path.
|
||
//
|
||
|
||
NextIrpSp->DeviceObject = IrpSp->DeviceObject;
|
||
|
||
//
|
||
// Since this is Paging file IO, we'll just ignore the verify bit.
|
||
//
|
||
|
||
if (FlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ||
|
||
(Fcb->Vcb->VerifyThread == KeGetCurrentThread())) {
|
||
|
||
SetFlag( IrpSp->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( AssocIrp,
|
||
&RxPagingFileCompletionRoutine,
|
||
Irp,
|
||
FALSE,
|
||
TRUE,
|
||
TRUE );
|
||
|
||
//
|
||
// Setup the next IRP stack location in the associated Irp for the disk
|
||
// driver beneath us.
|
||
//
|
||
|
||
NextIrpSp = IoGetNextIrpStackLocation( AssocIrp );
|
||
|
||
//
|
||
// Setup the Stack location to do a read from the disk driver.
|
||
//
|
||
|
||
NextIrpSp->MajorFunction = IrpSp->MajorFunction;
|
||
NextIrpSp->Parameters.Read.Length = NextByteCount;
|
||
NextIrpSp->Parameters.Read.ByteOffset.QuadPart = NextLbo;
|
||
|
||
(VOID)IoCallDriver( DeviceObject, AssocIrp );
|
||
|
||
//
|
||
// Now adjust everything for the next pass through the loop.
|
||
//
|
||
|
||
Vbo += NextByteCount;
|
||
BufferOffset += NextByteCount;
|
||
ByteCount -= NextByteCount;
|
||
|
||
//
|
||
// Try to lookup the next run (if we are not done).
|
||
//
|
||
|
||
CurrentIndex += 1;
|
||
|
||
if ( CurrentIndex <= LastIndex ) {
|
||
|
||
ASSERT( ByteCount != 0 );
|
||
|
||
FsRtlGetNextMcbEntry( &Fcb->Mcb,
|
||
CurrentIndex,
|
||
&NextVbo,
|
||
&NextLbo,
|
||
&NextByteCount );
|
||
|
||
ASSERT( NextVbo == Vbo );
|
||
}
|
||
} // while ( CurrentIndex <= LastIndex )
|
||
|
||
DebugTrace(-1, Dbg, "RxPagingFileIo -> VOID\n", 0);
|
||
return;
|
||
}
|
||
|
||
RXSTATUS
|
||
RxNonCachedIo (
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PIRP Irp,
|
||
IN PFCB FcbOrDcb,
|
||
IN ULONG StartingVbo,
|
||
IN ULONG ByteCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs the non-cached disk io described in its parameters.
|
||
The choice of a single run is made if possible, otherwise multiple runs
|
||
are executed.
|
||
|
||
Arguments:
|
||
|
||
RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
|
||
|
||
Irp - Supplies the requesting Irp.
|
||
|
||
FcbOrDcb - Supplies the file to act on.
|
||
|
||
StartingVbo - The starting point for the operation.
|
||
|
||
ByteCount - The lengh of the operation.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Declare some local variables for enumeration through the
|
||
// runs of the file, and an array to store parameters for
|
||
// parallel I/Os
|
||
//
|
||
|
||
BOOLEAN Wait;
|
||
|
||
LBO NextLbo;
|
||
VBO NextVbo;
|
||
ULONG NextByteCount;
|
||
BOOLEAN NextIsAllocated;
|
||
|
||
LBO LastLbo;
|
||
ULONG LastByteCount;
|
||
BOOLEAN LastIsAllocated;
|
||
|
||
ULONG FirstIndex;
|
||
ULONG CurrentIndex;
|
||
ULONG LastIndex;
|
||
|
||
ULONG NextRun;
|
||
ULONG BufferOffset;
|
||
ULONG OriginalByteCount;
|
||
|
||
IO_RUN StackIoRuns[RDBSS_MAX_IO_RUNS_ON_STACK];
|
||
PIO_RUN IoRuns;
|
||
|
||
DebugTrace(+1, Dbg, "RxNonCachedIo\n", 0);
|
||
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
|
||
DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
|
||
DebugTrace( 0, Dbg, "FcbOrDcb = %08lx\n", FcbOrDcb );
|
||
DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo );
|
||
DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount );
|
||
//no longer used DebugTrace( 0, Dbg, "Context = %08lx\n", Context );
|
||
|
||
//
|
||
// Initialize some locals.
|
||
//
|
||
|
||
NextRun = 0;
|
||
BufferOffset = 0;
|
||
OriginalByteCount = ByteCount;
|
||
|
||
Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
|
||
|
||
//
|
||
// For nonbuffered I/O, we need the buffer locked in all
|
||
// cases.
|
||
//
|
||
// This call may raise. If this call succeeds and a subsequent
|
||
// condition is raised, the buffers are unlocked automatically
|
||
// by the I/O system when the request is completed, via the
|
||
// Irp->MdlAddress field.
|
||
//
|
||
|
||
RxLockUserBuffer( RxContext,
|
||
(RxContext->MajorFunction == IRP_MJ_READ) ?
|
||
IoWriteAccess : IoReadAccess,
|
||
ByteCount );
|
||
|
||
#if 0 // The corruption was happening on the SCSI bus. (DavidGoe 1/11/93)
|
||
|
||
//
|
||
// If we are writing a directory, add a spot check here that
|
||
// what we are writing is really a directory.
|
||
//
|
||
|
||
if ( !FlagOn(FcbOrDcb->Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
|
||
(NodeType(FcbOrDcb) != RDBSS_NTC_FCB) &&
|
||
(RxContext->MajorFunction == IRP_MJ_WRITE) ) {
|
||
|
||
PDIRENT Dirent;
|
||
|
||
Dirent = RxMapUserBuffer( RxContext, Irp );
|
||
|
||
//
|
||
// For the first page of a non-root directory, make sure that
|
||
// . and .. are present.
|
||
//
|
||
|
||
if ( (StartingVbo == 0) &&
|
||
(NodeType(FcbOrDcb) != RDBSS_NTC_ROOT_DCB) ) {
|
||
|
||
if ( (RtlCompareMemory( (PUCHAR)Dirent++,
|
||
". ",
|
||
11 ) != 11) ||
|
||
(RtlCompareMemory( (PUCHAR)Dirent,
|
||
".. ",
|
||
11 ) != 11) ) {
|
||
|
||
RxBugCheck( 0, 0, 0 );
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Check that all the reserved bit in the second dirent are
|
||
// zero. (The first one contains our dirty bit in the root dir)
|
||
//
|
||
|
||
PULONG Zeros;
|
||
|
||
Dirent++;
|
||
|
||
Zeros = (PULONG)&Dirent->Reserved[0];
|
||
|
||
if ( (Dirent->FileName[0] != 0xE5) &&
|
||
((*Zeros != 0) || (*(Zeros+1) != 0)) ) {
|
||
|
||
RxBugCheck( 0, 0, 0 );
|
||
}
|
||
}
|
||
}
|
||
#endif //0
|
||
|
||
//
|
||
// Try to lookup the first run. If there is just a single run,
|
||
// we may just be able to pass it on.
|
||
//
|
||
|
||
RxLookupFileAllocation( RxContext,
|
||
FcbOrDcb,
|
||
StartingVbo,
|
||
&NextLbo,
|
||
&NextByteCount,
|
||
&NextIsAllocated,
|
||
&FirstIndex );
|
||
|
||
//
|
||
// We just added the allocation, thus there must be at least
|
||
// one entry in the mcb corresponding to our write, ie.
|
||
// NextIsAllocated must be true. If not, the pre-existing file
|
||
// must have an allocation error.
|
||
//
|
||
|
||
if ( !NextIsAllocated ) {
|
||
|
||
RxPopUpFileCorrupt( RxContext, FcbOrDcb );
|
||
|
||
RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
|
||
}
|
||
|
||
//
|
||
// If the request was not aligned correctly, read in the first
|
||
// part first.
|
||
//
|
||
|
||
|
||
//
|
||
// 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 );
|
||
|
||
RxSingleAsync( RxContext,
|
||
FcbOrDcb->Vcb,
|
||
NextLbo,
|
||
ByteCount,
|
||
Irp );
|
||
|
||
if (!Wait) {
|
||
|
||
DebugTrace(-1, Dbg, "RxNonCachedIo -> RxStatus(PENDING\n)", 0);
|
||
return RxStatus(PENDING);
|
||
|
||
} else {
|
||
|
||
RxWaitSync( RxContext );
|
||
|
||
DebugTrace(-1, Dbg, "RxNonCachedIo -> 0x%08lx\n", Irp->IoStatus.Status);
|
||
return Irp->IoStatus.Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If there we can't wait, and there are more runs than we can handle,
|
||
// we will have to post this request.
|
||
//
|
||
|
||
RxLookupFileAllocation( RxContext,
|
||
FcbOrDcb,
|
||
StartingVbo + ByteCount - 1,
|
||
&LastLbo,
|
||
&LastByteCount,
|
||
&LastIsAllocated,
|
||
&LastIndex );
|
||
|
||
//
|
||
// Since we already added the allocation for the whole
|
||
// write, assert that we find runs until ByteCount == 0
|
||
// Otherwise this file is corrupt.
|
||
//
|
||
|
||
if ( !LastIsAllocated ) {
|
||
|
||
RxPopUpFileCorrupt( RxContext, FcbOrDcb );
|
||
|
||
RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
|
||
}
|
||
|
||
if (LastIndex - FirstIndex + 1 > RDBSS_MAX_IO_RUNS_ON_STACK) {
|
||
|
||
IoRuns = FsRtlAllocatePool(PagedPool,
|
||
(LastIndex - FirstIndex + 1) * sizeof(IO_RUN));
|
||
|
||
} else {
|
||
|
||
IoRuns = StackIoRuns;
|
||
}
|
||
|
||
CurrentIndex = FirstIndex;
|
||
|
||
//
|
||
// Loop while there are still byte writes to satisfy.
|
||
//
|
||
|
||
while (CurrentIndex <= LastIndex) {
|
||
|
||
//
|
||
// If next run is larger than we need, "ya get what you need".
|
||
//
|
||
|
||
if (NextByteCount > ByteCount) {
|
||
NextByteCount = ByteCount;
|
||
}
|
||
|
||
//
|
||
// Now that we have properly bounded this piece of the
|
||
// transfer, it is time to write it.
|
||
//
|
||
// We remember each piece of a parallel run by saving the
|
||
// essential information in the IoRuns array. The tranfers
|
||
// are started up in parallel below.
|
||
//
|
||
|
||
IoRuns[NextRun].Vbo = StartingVbo;
|
||
IoRuns[NextRun].Lbo = NextLbo;
|
||
IoRuns[NextRun].Offset = BufferOffset;
|
||
IoRuns[NextRun].ByteCount = NextByteCount;
|
||
NextRun += 1;
|
||
|
||
//
|
||
// Now adjust everything for the next pass through the loop.
|
||
//
|
||
|
||
StartingVbo += NextByteCount;
|
||
BufferOffset += NextByteCount;
|
||
ByteCount -= NextByteCount;
|
||
|
||
//
|
||
// Try to lookup the next run (if we are not done).
|
||
//
|
||
|
||
CurrentIndex += 1;
|
||
|
||
if ( CurrentIndex <= LastIndex ) {
|
||
|
||
ASSERT( ByteCount != 0 );
|
||
|
||
FsRtlGetNextMcbEntry( &FcbOrDcb->Mcb,
|
||
CurrentIndex,
|
||
&NextVbo,
|
||
&NextLbo,
|
||
&NextByteCount );
|
||
|
||
ASSERT( NextVbo == StartingVbo );
|
||
}
|
||
|
||
} // while ( CurrentIndex <= LastIndex )
|
||
|
||
//
|
||
// 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 = RxStatus(SUCCESS);
|
||
Irp->IoStatus.Information = OriginalByteCount;
|
||
|
||
//
|
||
// OK, now do the I/O.
|
||
//
|
||
|
||
try {
|
||
|
||
RxMultipleAsync( RxContext,
|
||
FcbOrDcb->Vcb,
|
||
Irp,
|
||
NextRun,
|
||
IoRuns );
|
||
|
||
} finally {
|
||
|
||
if (IoRuns != StackIoRuns) {
|
||
|
||
ExFreePool( IoRuns );
|
||
}
|
||
}
|
||
|
||
if (!Wait) {
|
||
|
||
DebugTrace(-1, Dbg, "RxNonCachedIo -> RxStatus(PENDING\n)", 0);
|
||
return RxStatus(PENDING);
|
||
}
|
||
|
||
RxWaitSync( RxContext );
|
||
|
||
DebugTrace(-1, Dbg, "RxNonCachedIo -> 0x%08lx\n", Irp->IoStatus.Status);
|
||
return Irp->IoStatus.Status;
|
||
}
|
||
|
||
|
||
VOID
|
||
RxNonCachedNonAlignedRead (
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PIRP Irp,
|
||
IN PFCB FcbOrDcb,
|
||
IN ULONG StartingVbo,
|
||
IN ULONG ByteCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs the non-cached disk io described in its parameters.
|
||
This routine differs from the above in that the range does not have to be
|
||
sector aligned. This accomplished with the use of intermediate buffers.
|
||
|
||
Arguments:
|
||
|
||
RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
|
||
|
||
Irp - Supplies the requesting Irp.
|
||
|
||
FcbOrDcb - Supplies the file to act on.
|
||
|
||
StartingVbo - The starting point for the operation.
|
||
|
||
ByteCount - The lengh of the operation.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Declare some local variables for enumeration through the
|
||
// runs of the file, and an array to store parameters for
|
||
// parallel I/Os
|
||
//
|
||
|
||
LBO NextLbo;
|
||
ULONG NextByteCount;
|
||
BOOLEAN NextIsAllocated;
|
||
|
||
ULONG SectorSize;
|
||
ULONG BytesToCopy;
|
||
ULONG OriginalByteCount;
|
||
ULONG OriginalStartingVbo;
|
||
|
||
PUCHAR UserBuffer;
|
||
PUCHAR DiskBuffer = NULL;
|
||
|
||
PMDL Mdl;
|
||
PMDL SavedMdl;
|
||
|
||
DebugTrace(+1, Dbg, "RxNonCachedNonAlignedRead\n", 0);
|
||
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
|
||
DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
|
||
DebugTrace( 0, Dbg, "FcbOrDcb = %08lx\n", FcbOrDcb );
|
||
DebugTrace( 0, Dbg, "StartingVbo = %08lx\n", StartingVbo );
|
||
DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount );
|
||
|
||
//
|
||
// Initialize some locals.
|
||
//
|
||
|
||
OriginalByteCount = ByteCount;
|
||
OriginalStartingVbo = StartingVbo;
|
||
SectorSize = FcbOrDcb->Vcb->Bpb.BytesPerSector;
|
||
|
||
ASSERT( FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT) );
|
||
|
||
//
|
||
// For nonbuffered I/O, we need the buffer locked in all
|
||
// cases.
|
||
//
|
||
// This call may raise. If this call succeeds and a subsequent
|
||
// condition is raised, the buffers are unlocked automatically
|
||
// by the I/O system when the request is completed, via the
|
||
// Irp->MdlAddress field.
|
||
//
|
||
|
||
RxLockUserBuffer( RxContext,
|
||
IoWriteAccess,
|
||
ByteCount );
|
||
|
||
UserBuffer = RxMapUserBuffer( RxContext );
|
||
|
||
//
|
||
// Allocate the local buffer
|
||
//
|
||
|
||
DiskBuffer = FsRtlAllocatePool( NonPagedPoolCacheAligned,
|
||
ROUND_TO_PAGES( SectorSize ));
|
||
|
||
//
|
||
// We use a try block here to ensure the buffer is freed, and to
|
||
// fill in the correct byte count in the Iosb.Information field.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// If the beginning of the request was not aligned correctly, read in
|
||
// the first part first.
|
||
//
|
||
|
||
if ( StartingVbo & (SectorSize - 1) ) {
|
||
|
||
VBO Hole;
|
||
|
||
//
|
||
// Try to lookup the first run.
|
||
//
|
||
|
||
RxLookupFileAllocation( RxContext,
|
||
FcbOrDcb,
|
||
StartingVbo,
|
||
&NextLbo,
|
||
&NextByteCount,
|
||
&NextIsAllocated,
|
||
NULL );
|
||
|
||
//
|
||
// We just added the allocation, thus there must be at least
|
||
// one entry in the mcb corresponding to our write, ie.
|
||
// NextIsAllocated must be true. If not, the pre-existing file
|
||
// must have an allocation error.
|
||
//
|
||
|
||
if ( !NextIsAllocated ) {
|
||
|
||
RxPopUpFileCorrupt( RxContext, FcbOrDcb );
|
||
|
||
RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
|
||
}
|
||
|
||
RxSingleNonAlignedSync( RxContext,
|
||
FcbOrDcb->Vcb,
|
||
DiskBuffer,
|
||
NextLbo & ~(SectorSize - 1),
|
||
SectorSize,
|
||
Irp );
|
||
|
||
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
|
||
|
||
try_return( NOTHING );
|
||
}
|
||
|
||
//
|
||
// Now copy the part of the first sector that we want to the user
|
||
// buffer.
|
||
//
|
||
|
||
Hole = StartingVbo & (SectorSize - 1);
|
||
|
||
BytesToCopy = ByteCount >= SectorSize - Hole ?
|
||
SectorSize - Hole : ByteCount;
|
||
|
||
RtlCopyMemory( UserBuffer, DiskBuffer + Hole, BytesToCopy );
|
||
|
||
StartingVbo += BytesToCopy;
|
||
ByteCount -= BytesToCopy;
|
||
|
||
if ( ByteCount == 0 ) {
|
||
|
||
try_return( NOTHING );
|
||
}
|
||
}
|
||
|
||
ASSERT( (StartingVbo & (SectorSize - 1)) == 0 );
|
||
|
||
//
|
||
// If there is a tail part that is not sector aligned, read it.
|
||
//
|
||
|
||
if ( ByteCount & (SectorSize - 1) ) {
|
||
|
||
VBO LastSectorVbo;
|
||
|
||
LastSectorVbo = StartingVbo + (ByteCount & ~(SectorSize - 1));
|
||
|
||
//
|
||
// Try to lookup the last part of the requested range.
|
||
//
|
||
|
||
RxLookupFileAllocation( RxContext,
|
||
FcbOrDcb,
|
||
LastSectorVbo,
|
||
&NextLbo,
|
||
&NextByteCount,
|
||
&NextIsAllocated,
|
||
NULL );
|
||
|
||
//
|
||
// We just added the allocation, thus there must be at least
|
||
// one entry in the mcb corresponding to our write, ie.
|
||
// NextIsAllocated must be true. If not, the pre-existing file
|
||
// must have an allocation error.
|
||
//
|
||
|
||
if ( !NextIsAllocated ) {
|
||
|
||
RxPopUpFileCorrupt( RxContext, FcbOrDcb );
|
||
|
||
RxRaiseStatus( RxContext, RxStatus(FILE_CORRUPT_ERROR) );
|
||
}
|
||
|
||
RxSingleNonAlignedSync( RxContext,
|
||
FcbOrDcb->Vcb,
|
||
DiskBuffer,
|
||
NextLbo,
|
||
SectorSize,
|
||
Irp );
|
||
|
||
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
|
||
|
||
try_return( NOTHING );
|
||
}
|
||
|
||
//
|
||
// Now copy over the part of this last sector that we need.
|
||
//
|
||
|
||
BytesToCopy = ByteCount & (SectorSize - 1);
|
||
|
||
UserBuffer += LastSectorVbo - OriginalStartingVbo;
|
||
|
||
RtlCopyMemory( UserBuffer, DiskBuffer, BytesToCopy );
|
||
|
||
ByteCount -= BytesToCopy;
|
||
|
||
if ( ByteCount == 0 ) {
|
||
|
||
try_return( NOTHING );
|
||
}
|
||
}
|
||
|
||
ASSERT( ((StartingVbo | ByteCount) & (SectorSize - 1)) == 0 );
|
||
|
||
//
|
||
// Now build a Mdl describing the sector aligned balance of the transfer,
|
||
// and put it in the Irp, and read that part.
|
||
//
|
||
|
||
SavedMdl = Irp->MdlAddress;
|
||
Irp->MdlAddress = NULL;
|
||
|
||
UserBuffer = MmGetMdlVirtualAddress( SavedMdl );
|
||
|
||
Mdl = IoAllocateMdl( UserBuffer + (StartingVbo - OriginalStartingVbo),
|
||
ByteCount,
|
||
FALSE,
|
||
FALSE,
|
||
Irp );
|
||
|
||
if (Mdl == NULL) {
|
||
|
||
Irp->MdlAddress = SavedMdl;
|
||
RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
|
||
}
|
||
|
||
IoBuildPartialMdl( SavedMdl,
|
||
Mdl,
|
||
UserBuffer + (StartingVbo - OriginalStartingVbo),
|
||
ByteCount );
|
||
|
||
//
|
||
// Try to read in the pages.
|
||
//
|
||
|
||
try {
|
||
|
||
RxNonCachedIo( RxContext,
|
||
Irp,
|
||
FcbOrDcb,
|
||
StartingVbo,
|
||
ByteCount );
|
||
|
||
} finally {
|
||
|
||
IoFreeMdl( Irp->MdlAddress );
|
||
|
||
Irp->MdlAddress = SavedMdl;
|
||
}
|
||
|
||
try_exit: NOTHING;
|
||
|
||
} finally {
|
||
|
||
ExFreePool( DiskBuffer );
|
||
|
||
if ( !AbnormalTermination() && NT_SUCCESS(Irp->IoStatus.Status) ) {
|
||
|
||
Irp->IoStatus.Information = OriginalByteCount;
|
||
|
||
//
|
||
// We now flush the user's buffer to memory.
|
||
//
|
||
|
||
KeFlushIoBuffers( Irp->MdlAddress, TRUE, FALSE );
|
||
}
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "RxNonCachedNonAlignedRead -> VOID\n", 0);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
RxMultipleAsync (
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PVCB Vcb,
|
||
IN PIRP MasterIrp,
|
||
IN ULONG MultipleIrpCount,
|
||
IN PIO_RUN IoRuns
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine first does the initial setup required of a Master IRP that is
|
||
going to be completed using associated IRPs. This routine should not
|
||
be used if only one async request is needed, instead the single read/write
|
||
async routines should be called.
|
||
|
||
A context parameter is initialized, to serve as a communications area
|
||
between here and the common completion routine. This initialization
|
||
includes allocation of a spinlock. The spinlock is deallocated in the
|
||
RxWaitSync routine, so it is essential that the caller insure that
|
||
this routine is always called under all circumstances following a call
|
||
to this routine.
|
||
|
||
Next this routine reads or writes one or more contiguous sectors from
|
||
a device asynchronously, and is used if there are multiple reads for a
|
||
master IRP. A completion routine is used to synchronize with the
|
||
completion of all of the I/O requests started by calls to this routine.
|
||
|
||
Also, prior to calling this routine the caller must initialize the
|
||
IoStatus field in the Context, with the correct success status and byte
|
||
count which are expected if all of the parallel transfers complete
|
||
successfully. After return this status will be unchanged if all requests
|
||
were, in fact, successful. However, if one or more errors occur, the
|
||
IoStatus will be modified to reflect the error status and byte count
|
||
from the first run (by Vbo) which encountered an error. I/O status
|
||
from all subsequent runs will not be indicated.
|
||
|
||
Arguments:
|
||
|
||
RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
|
||
|
||
Vcb - Supplies the device to be read
|
||
|
||
MasterIrp - Supplies the master Irp.
|
||
|
||
MulitpleIrpCount - Supplies the number of multiple async requests
|
||
that will be issued against the master irp.
|
||
|
||
IoRuns - Supplies an array containing the Vbo, Lbo, BufferOffset, and
|
||
ByteCount for all the runs to executed in parallel.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PMDL Mdl;
|
||
BOOLEAN Wait;
|
||
PRDBSS_IO_CONTEXT Context;
|
||
|
||
ULONG UnwindRunCount = 0;
|
||
|
||
BOOLEAN ExceptionExpected = TRUE;
|
||
|
||
BOOLEAN CalledByRxVerifyVolume = FALSE;
|
||
|
||
DebugTrace(+1, Dbg, "RxMultipleAsync\n", 0);
|
||
DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
|
||
DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
|
||
DebugTrace( 0, Dbg, "MasterIrp = %08lx\n", MasterIrp );
|
||
DebugTrace( 0, Dbg, "MultipleIrpCount = %08lx\n", MultipleIrpCount );
|
||
DebugTrace( 0, Dbg, "IoRuns = %08lx\n", IoRuns );
|
||
|
||
//
|
||
// If this I/O originating during RxVerifyVolume, bypass the
|
||
// verify logic.
|
||
//
|
||
|
||
if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
|
||
|
||
CalledByRxVerifyVolume = TRUE;
|
||
}
|
||
|
||
//
|
||
// Set up things according to whether this is truely async.
|
||
//
|
||
|
||
Wait = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_WAIT );
|
||
|
||
Context = RxContext->RxIoContext;
|
||
|
||
//
|
||
// Finish initializing Context, for use in Read/Write Multiple Asynch.
|
||
//
|
||
|
||
Context->MasterIrp = MasterIrp;
|
||
|
||
try {
|
||
|
||
//
|
||
// Itterate through the runs, doing everything that can fail
|
||
//
|
||
|
||
for ( UnwindRunCount = 0;
|
||
UnwindRunCount < MultipleIrpCount;
|
||
UnwindRunCount++ ) {
|
||
|
||
//
|
||
// Create an associated IRP, making sure there is one stack entry for
|
||
// us, as well.
|
||
//
|
||
|
||
IoRuns[UnwindRunCount].SavedIrp = 0;
|
||
|
||
Irp = IoMakeAssociatedIrp( MasterIrp,
|
||
(CCHAR)(Vcb->TargetDeviceObject->StackSize + 1) );
|
||
|
||
if (Irp == NULL) {
|
||
|
||
RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
|
||
}
|
||
|
||
IoRuns[UnwindRunCount].SavedIrp = Irp;
|
||
|
||
//
|
||
// Allocate and build a partial Mdl for the request.
|
||
//
|
||
|
||
Mdl = IoAllocateMdl( (PCHAR)MasterIrp->UserBuffer +
|
||
IoRuns[UnwindRunCount].Offset,
|
||
IoRuns[UnwindRunCount].ByteCount,
|
||
FALSE,
|
||
FALSE,
|
||
Irp );
|
||
|
||
if (Mdl == NULL) {
|
||
|
||
RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
|
||
}
|
||
|
||
//
|
||
// Sanity Check
|
||
//
|
||
|
||
ASSERT( Mdl == Irp->MdlAddress );
|
||
|
||
IoBuildPartialMdl( MasterIrp->MdlAddress,
|
||
Mdl,
|
||
(PCHAR)MasterIrp->UserBuffer +
|
||
IoRuns[UnwindRunCount].Offset,
|
||
IoRuns[UnwindRunCount].ByteCount );
|
||
|
||
//
|
||
// Get the first IRP stack location in the associated Irp
|
||
//
|
||
|
||
IoSetNextIrpStackLocation( Irp );
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
//
|
||
// Setup the Stack location to describe our read.
|
||
//
|
||
|
||
IrpSp->MajorFunction = RxContext->MajorFunction;
|
||
IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].ByteCount;
|
||
IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].Vbo;
|
||
|
||
//
|
||
// Set up the completion routine address in our stack frame.
|
||
//
|
||
|
||
IoSetCompletionRoutine( Irp,
|
||
Wait ?
|
||
&RxMultiSyncCompletionRoutine :
|
||
&RxMultiAsyncCompletionRoutine,
|
||
Context,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE );
|
||
|
||
//
|
||
// Setup the next IRP stack location in the associated Irp for the disk
|
||
// driver beneath us.
|
||
//
|
||
|
||
IrpSp = IoGetNextIrpStackLocation( Irp );
|
||
|
||
//
|
||
// Setup the Stack location to do a read from the disk driver.
|
||
//
|
||
|
||
IrpSp->MajorFunction = RxContext->MajorFunction;
|
||
IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].ByteCount;
|
||
IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].Lbo;
|
||
|
||
//
|
||
// If this Irp is the result of a WriteThough operation,
|
||
// tell the device to write it through.
|
||
//
|
||
|
||
if (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH)) {
|
||
|
||
SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
|
||
}
|
||
|
||
//
|
||
// If this I/O originating during RxVerifyVolume, bypass the
|
||
// verify logic.
|
||
//
|
||
|
||
if ( CalledByRxVerifyVolume ) {
|
||
|
||
SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now we no longer expect an exception. If the driver raises, we
|
||
// must bugcheck, because we do not know how to recover from that
|
||
// case.
|
||
//
|
||
|
||
ExceptionExpected = FALSE;
|
||
|
||
//
|
||
// We only need to set the associated IRP count in the master irp to
|
||
// make it a master IRP. But we set the count to one more than our
|
||
// caller requested, because we do not want the I/O system to complete
|
||
// the I/O. We also set our own count.
|
||
//
|
||
|
||
Context->IrpCount = MultipleIrpCount;
|
||
MasterIrp->AssociatedIrp.IrpCount = MultipleIrpCount;
|
||
|
||
if (Wait) {
|
||
|
||
MasterIrp->AssociatedIrp.IrpCount += 1;
|
||
}
|
||
|
||
//
|
||
// Now that all the dangerous work is done, issue the read requests
|
||
//
|
||
|
||
for (UnwindRunCount = 0;
|
||
UnwindRunCount < MultipleIrpCount;
|
||
UnwindRunCount++) {
|
||
|
||
Irp = IoRuns[UnwindRunCount].SavedIrp;
|
||
|
||
DebugDoit( RxIoCallDriverCount += 1);
|
||
|
||
//
|
||
// If IoCallDriver returns an error, it has completed the Irp
|
||
// and the error will be caught by our completion routines
|
||
// and dealt with as a normal IO error.
|
||
//
|
||
|
||
(VOID)RxLowLevelReadWrite( RxContext,
|
||
Vcb->TargetDeviceObject,
|
||
Irp,
|
||
Vcb );
|
||
}
|
||
|
||
} finally {
|
||
|
||
ULONG i;
|
||
|
||
DebugUnwind( RxMultipleAsync );
|
||
|
||
//
|
||
// Only allocating the spinlock, making the associated Irps
|
||
// and allocating the Mdls can fail.
|
||
//
|
||
|
||
if ( AbnormalTermination() ) {
|
||
|
||
//
|
||
// If the driver raised, we are hosed. He is not supposed to raise,
|
||
// and it is impossible for us to figure out how to clean up.
|
||
//
|
||
|
||
if (!ExceptionExpected) {
|
||
ASSERT( ExceptionExpected );
|
||
RxBugCheck( 0, 0, 0 );
|
||
}
|
||
|
||
//
|
||
// Unwind
|
||
//
|
||
|
||
for (i = 0; i <= UnwindRunCount; i++) {
|
||
|
||
if ( (Irp = IoRuns[i].SavedIrp) != NULL ) {
|
||
|
||
if ( Irp->MdlAddress != NULL ) {
|
||
|
||
IoFreeMdl( Irp->MdlAddress );
|
||
}
|
||
|
||
IoFreeIrp( Irp );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DebugTrace(-1, Dbg, "RxMultipleAsync -> VOID\n", 0);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
RxSingleAsync (
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PVCB Vcb,
|
||
IN LBO Lbo,
|
||
IN ULONG ByteCount,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine reads or writes one or more contiguous sectors from a device
|
||
asynchronously, and is used if there is only one read necessary to
|
||
complete the IRP. It implements the read by simply filling
|
||
in the next stack frame in the Irp, and passing it on. The transfer
|
||
occurs to the single buffer originally specified in the user request.
|
||
|
||
Arguments:
|
||
|
||
RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
|
||
|
||
Vcb - Supplies the device to read
|
||
|
||
Lbo - Supplies the starting Logical Byte Offset to begin reading from
|
||
|
||
ByteCount - Supplies the number of bytes to read from the device
|
||
|
||
Irp - Supplies the master Irp to associated with the async
|
||
request.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
DebugTrace(+1, Dbg, "RxSingleAsync\n", 0);
|
||
DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
|
||
DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
|
||
DebugTrace( 0, Dbg, "Lbo = %08lx\n", Lbo);
|
||
DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
|
||
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
|
||
|
||
//
|
||
// Set up the completion routine address in our stack frame.
|
||
//
|
||
|
||
IoSetCompletionRoutine( Irp,
|
||
FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT) ?
|
||
&RxSingleSyncCompletionRoutine :
|
||
&RxSingleAsyncCompletionRoutine,
|
||
RxContext->RxIoContext,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE );
|
||
|
||
//
|
||
// Setup the next IRP stack location in the associated Irp for the disk
|
||
// driver beneath us.
|
||
//
|
||
|
||
IrpSp = IoGetNextIrpStackLocation( Irp );
|
||
|
||
//
|
||
// Setup the Stack location to do a read from the disk driver.
|
||
//
|
||
|
||
IrpSp->MajorFunction = RxContext->MajorFunction;
|
||
IrpSp->Parameters.Read.Length = ByteCount;
|
||
IrpSp->Parameters.Read.ByteOffset.QuadPart = Lbo;
|
||
|
||
//
|
||
// If this Irp is the result of a WriteThough operation,
|
||
// tell the device to write it through.
|
||
//
|
||
|
||
if (FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH)) {
|
||
|
||
SetFlag( IrpSp->Flags, SL_WRITE_THROUGH );
|
||
}
|
||
|
||
//
|
||
// If this I/O originating during RxVerifyVolume, bypass the
|
||
// verify logic.
|
||
//
|
||
|
||
if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
|
||
|
||
SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
|
||
}
|
||
|
||
//
|
||
// Issue the read request
|
||
//
|
||
|
||
DebugDoit( RxIoCallDriverCount += 1);
|
||
|
||
//
|
||
// If IoCallDriver returns an error, it has completed the Irp
|
||
// and the error will be caught by our completion routines
|
||
// and dealt with as a normal IO error.
|
||
//
|
||
|
||
(VOID)RxLowLevelReadWrite( RxContext,
|
||
Vcb->TargetDeviceObject,
|
||
Irp,
|
||
Vcb );
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DebugTrace(-1, Dbg, "RxSingleAsync -> VOID\n", 0);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
RxSingleNonAlignedSync (
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PVCB Vcb,
|
||
IN PUCHAR Buffer,
|
||
IN LBO Lbo,
|
||
IN ULONG ByteCount,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine reads or writes one or more contiguous sectors from a device
|
||
Synchronously, and does so to a buffer that must come from non paged
|
||
pool. It saves a pointer to the Irp's original Mdl, and creates a new
|
||
one describing the given buffer. It implements the read by simply filling
|
||
in the next stack frame in the Irp, and passing it on. The transfer
|
||
occurs to the single buffer originally specified in the user request.
|
||
|
||
Arguments:
|
||
|
||
RxContext->MajorFunction - Supplies either IRP_MJ_READ or IRP_MJ_WRITE.
|
||
|
||
Vcb - Supplies the device to read
|
||
|
||
Buffer - Supplies a buffer from non-paged pool.
|
||
|
||
Lbo - Supplies the starting Logical Byte Offset to begin reading from
|
||
|
||
ByteCount - Supplies the number of bytes to read from the device
|
||
|
||
Irp - Supplies the master Irp to associated with the async
|
||
request.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
PMDL Mdl;
|
||
PMDL SavedMdl;
|
||
|
||
DebugTrace(+1, Dbg, "RxSingleNonAlignedAsync\n", 0);
|
||
DebugTrace( 0, Dbg, "MajorFunction = %08lx\n", RxContext->MajorFunction );
|
||
DebugTrace( 0, Dbg, "Vcb = %08lx\n", Vcb );
|
||
DebugTrace( 0, Dbg, "Buffer = %08lx\n", Buffer );
|
||
DebugTrace( 0, Dbg, "Lbo = %08lx\n", Lbo);
|
||
DebugTrace( 0, Dbg, "ByteCount = %08lx\n", ByteCount);
|
||
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
|
||
|
||
//
|
||
// Create a new Mdl describing the buffer, saving the current one in the
|
||
// Irp
|
||
//
|
||
|
||
SavedMdl = Irp->MdlAddress;
|
||
|
||
Irp->MdlAddress = 0;
|
||
|
||
Mdl = IoAllocateMdl( Buffer,
|
||
ByteCount,
|
||
FALSE,
|
||
FALSE,
|
||
Irp );
|
||
|
||
if (Mdl == NULL) {
|
||
|
||
Irp->MdlAddress = SavedMdl;
|
||
|
||
RxRaiseStatus( RxContext, RxStatus(INSUFFICIENT_RESOURCES) );
|
||
}
|
||
|
||
//
|
||
// Lock the new Mdl in memory.
|
||
//
|
||
|
||
try {
|
||
|
||
MmProbeAndLockPages( Mdl, KernelMode, IoWriteAccess );
|
||
|
||
} finally {
|
||
|
||
if ( AbnormalTermination() ) {
|
||
|
||
IoFreeMdl( Mdl );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set up the completion routine address in our stack frame.
|
||
//
|
||
|
||
IoSetCompletionRoutine( Irp,
|
||
&RxSingleSyncCompletionRoutine,
|
||
RxContext->RxIoContext,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE );
|
||
|
||
//
|
||
// Setup the next IRP stack location in the associated Irp for the disk
|
||
// driver beneath us.
|
||
//
|
||
|
||
IrpSp = IoGetNextIrpStackLocation( Irp );
|
||
|
||
//
|
||
// Setup the Stack location to do a read from the disk driver.
|
||
//
|
||
|
||
IrpSp->MajorFunction = RxContext->MajorFunction;
|
||
IrpSp->Parameters.Read.Length = ByteCount;
|
||
IrpSp->Parameters.Read.ByteOffset.QuadPart = Lbo;
|
||
|
||
//
|
||
// If this I/O originating during RxVerifyVolume, bypass the
|
||
// verify logic.
|
||
//
|
||
|
||
if ( Vcb->VerifyThread == KeGetCurrentThread() ) {
|
||
|
||
SetFlag( IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME );
|
||
}
|
||
|
||
//
|
||
// Issue the read request
|
||
//
|
||
|
||
DebugDoit( RxIoCallDriverCount += 1);
|
||
|
||
//
|
||
// If IoCallDriver returns an error, it has completed the Irp
|
||
// and the error will be caught by our completion routines
|
||
// and dealt with as a normal IO error.
|
||
//
|
||
|
||
try {
|
||
|
||
(VOID)RxLowLevelReadWrite( RxContext,
|
||
Vcb->TargetDeviceObject,
|
||
Irp,
|
||
Vcb );
|
||
|
||
RxWaitSync( RxContext );
|
||
|
||
} finally {
|
||
|
||
MmUnlockPages( Mdl );
|
||
|
||
IoFreeMdl( Mdl );
|
||
|
||
Irp->MdlAddress = SavedMdl;
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DebugTrace(-1, Dbg, "RxSingleNonAlignedSync -> VOID\n", 0);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// Internal Support Routine
|
||
//
|
||
|
||
RXSTATUS
|
||
RxMultiSyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for all reads and writes started via
|
||
RxRead/WriteMultipleAsynch. It must synchronize its operation for
|
||
multiprocessor environments with itself on all other processors, via
|
||
a spin lock found via the Context parameter.
|
||
|
||
The completion routine has the following responsibilities:
|
||
|
||
If the individual request was completed with an error, then
|
||
this completion routine must see if this is the first error
|
||
(essentially by Vbo), and if so it must correctly reduce the
|
||
byte count and remember the error status in the Context.
|
||
|
||
If the IrpCount goes to 1, then it sets the event in the Context
|
||
parameter to signal the caller that all of the asynch requests
|
||
are done.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the file system device object.
|
||
|
||
Irp - Pointer to the associated Irp which is being completed. (This
|
||
Irp will no longer be accessible after this routine returns.)
|
||
|
||
Contxt - The context parameter which was specified for all of
|
||
the multiple asynch I/O requests for this MasterIrp.
|
||
|
||
Return Value:
|
||
|
||
The routine returns RxStatus(MORE_PROCESSING_REQUIRED) so that we can
|
||
immediately complete the Master Irp without being in a race condition
|
||
with the IoCompleteRequest thread trying to decrement the IrpCount in
|
||
the Master Irp.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PRDBSS_IO_CONTEXT Context = Contxt;
|
||
PIRP MasterIrp = Context->MasterIrp;
|
||
|
||
DebugTrace(+1, Dbg, "RxMultiSyncCompletionRoutine, Context = %08lx\n", Context );
|
||
|
||
//
|
||
// If we got an error (or verify required), remember it in the Irp
|
||
//
|
||
|
||
MasterIrp = Context->MasterIrp;
|
||
|
||
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
|
||
|
||
MasterIrp->IoStatus = Irp->IoStatus;
|
||
}
|
||
|
||
//
|
||
// We must do this here since IoCompleteRequest won't get a chance
|
||
// on this associated Irp.
|
||
//
|
||
|
||
IoFreeMdl( Irp->MdlAddress );
|
||
IoFreeIrp( Irp );
|
||
|
||
//
|
||
// Use a spin lock to synchronize access to Context->IrpCount.
|
||
//
|
||
|
||
if (ExInterlockedDecrementLong(&Context->IrpCount,
|
||
&RxData.StrucSupSpinLock) == RESULT_ZERO) {
|
||
|
||
KeSetEvent( &Context->Wait.SyncEvent, 0, FALSE );
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "RxMultiSyncCompletionRoutine -> SUCCESS\n", 0 );
|
||
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
|
||
return RxStatus(MORE_PROCESSING_REQUIRED);
|
||
}
|
||
|
||
|
||
//
|
||
// Internal Support Routine
|
||
//
|
||
|
||
RXSTATUS
|
||
RxMultiAsyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for all reads and writes started via
|
||
RxRead/WriteMultipleAsynch. It must synchronize its operation for
|
||
multiprocessor environments with itself on all other processors, via
|
||
a spin lock found via the Context parameter.
|
||
|
||
The completion routine has has the following responsibilities:
|
||
|
||
If the individual request was completed with an error, then
|
||
this completion routine must see if this is the first error
|
||
(essentially by Vbo), and if so it must correctly reduce the
|
||
byte count and remember the error status in the Context.
|
||
|
||
If the IrpCount goes to 1, then it sets the event in the Context
|
||
parameter to signal the caller that all of the asynch requests
|
||
are done.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the file system device object.
|
||
|
||
Irp - Pointer to the associated Irp which is being completed. (This
|
||
Irp will no longer be accessible after this routine returns.)
|
||
|
||
Contxt - The context parameter which was specified for all of
|
||
the multiple asynch I/O requests for this MasterIrp.
|
||
|
||
Return Value:
|
||
|
||
The routine returns RxStatus(MORE_PROCESSING_REQUIRED) so that we can
|
||
immediately complete the Master Irp without being in a race condition
|
||
with the IoCompleteRequest thread trying to decrement the IrpCount in
|
||
the Master Irp.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PRDBSS_IO_CONTEXT Context = Contxt;
|
||
PIRP MasterIrp = Context->MasterIrp;
|
||
|
||
DebugTrace(+1, Dbg, "RxMultiAsyncCompletionRoutine, Context = %08lx\n", Context );
|
||
|
||
//
|
||
// If we got an error (or verify required), remember it in the Irp
|
||
//
|
||
|
||
MasterIrp = Context->MasterIrp;
|
||
|
||
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
|
||
|
||
MasterIrp->IoStatus = Irp->IoStatus;
|
||
}
|
||
|
||
//
|
||
// Use a spin lock to synchronize access to Context->IrpCount.
|
||
//
|
||
|
||
if (ExInterlockedDecrementLong(&Context->IrpCount,
|
||
&RxData.StrucSupSpinLock) == RESULT_ZERO) {
|
||
|
||
if (NT_SUCCESS(MasterIrp->IoStatus.Status)) {
|
||
|
||
MasterIrp->IoStatus.Information =
|
||
Context->Wait.Async.RequestedByteCount;
|
||
|
||
//
|
||
// Now if this wasn't PagingIo, set either the read or write bit.
|
||
//
|
||
|
||
if (!FlagOn(MasterIrp->Flags, IRP_PAGING_IO)) {
|
||
|
||
SetFlag( Context->Wait.Async.FileObject->Flags,
|
||
IoGetCurrentIrpStackLocation(MasterIrp)->MajorFunction == IRP_MJ_READ ?
|
||
FO_FILE_FAST_IO_READ : FO_FILE_MODIFIED );
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this was a special async write, decrement the count. Set the
|
||
// event if this was the final outstanding I/O for the file. We will
|
||
// also want to queue an APC to deal with any error conditionions.
|
||
//
|
||
|
||
if ((Context->Wait.Async.NonPagedFcb) &&
|
||
(ExInterlockedAddUlong( &Context->Wait.Async.NonPagedFcb->OutstandingAsyncWrites,
|
||
0xffffffff,
|
||
&RxStrucSupSpinLock ) == 1)) {
|
||
|
||
KeSetEvent( Context->Wait.Async.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
|
||
}
|
||
|
||
//
|
||
// Now release the resource
|
||
//
|
||
|
||
if (Context->Wait.Async.Resource != NULL) {
|
||
|
||
ExReleaseResourceForThread( Context->Wait.Async.Resource,
|
||
Context->Wait.Async.ResourceThreadId );
|
||
}
|
||
|
||
//
|
||
// Mark the master Irp pending
|
||
//
|
||
|
||
IoMarkIrpPending( MasterIrp );
|
||
|
||
//
|
||
// and finally, free the context record.
|
||
//
|
||
|
||
ExFreePool( Context );
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "RxMultiAsyncCompletionRoutine -> SUCCESS\n", 0 );
|
||
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
|
||
return RxStatus(SUCCESS);
|
||
}
|
||
|
||
|
||
//
|
||
// Internal Support Routine
|
||
//
|
||
|
||
RXSTATUS
|
||
RxPagingFileCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID MasterIrp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for all reads and writes started via
|
||
RxPagingFileIo. It should only be invoked on error or cancel.
|
||
|
||
The completion routine has has the following responsibility:
|
||
|
||
Since the individual request was completed with an error,
|
||
this completion routine must stuff it into the master irp.
|
||
|
||
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
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the file system device object.
|
||
|
||
Irp - Pointer to the associated Irp which is being completed. (This
|
||
Irp will no longer be accessible after this routine returns.)
|
||
|
||
MasterIrp - Pointer to the master Irp.
|
||
|
||
Return Value:
|
||
|
||
Always returns RxStatus(SUCCESS).
|
||
|
||
--*/
|
||
|
||
{
|
||
RXSTATUS Status;
|
||
|
||
DebugTrace(+1, Dbg, "RxPagingFileCompletionRoutine, MasterIrp = %08lx\n", MasterIrp );
|
||
|
||
//
|
||
// If we got an error (or verify required), remember it in the Irp
|
||
//
|
||
|
||
ASSERT( !NT_SUCCESS( Irp->IoStatus.Status ));
|
||
|
||
//
|
||
// If we were invoked with an assoicated Irp, copy the error over.
|
||
//
|
||
|
||
if (Irp != MasterIrp) {
|
||
|
||
((PIRP)MasterIrp)->IoStatus = Irp->IoStatus;
|
||
}
|
||
|
||
//
|
||
// If this was a media error, we want to chkdsk /r the next time we boot.
|
||
//
|
||
|
||
if (FsRtlIsTotalDeviceFailure(Irp->IoStatus.Status)) {
|
||
|
||
Status = RxStatus(SUCCESS);
|
||
|
||
} else {
|
||
|
||
PCLEAN_AND_DIRTY_VOLUME_PACKET Packet;
|
||
|
||
//
|
||
// We are going to try to mark the volume needing recover.
|
||
// If we can't get pool, oh well....
|
||
//
|
||
|
||
Packet = ExAllocatePool(NonPagedPool, sizeof(CLEAN_AND_DIRTY_VOLUME_PACKET));
|
||
|
||
if ( Packet ) {
|
||
|
||
Packet->Vcb = &((PRDBSS_DEVICE_OBJECT)IoGetCurrentIrpStackLocation(Irp)->DeviceObject)->Vcb;
|
||
Packet->Irp = Irp;
|
||
|
||
ExInitializeWorkItem( &Packet->Item,
|
||
&RxFspMarkVolumeDirtyWithRecover,
|
||
Packet );
|
||
|
||
ExQueueWorkItem( &Packet->Item, CriticalWorkQueue );
|
||
|
||
Status = RxStatus(MORE_PROCESSING_REQUIRED);
|
||
|
||
} else {
|
||
|
||
Status = RxStatus(SUCCESS);
|
||
}
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "RxPagingFileCompletionRoutine => (RxStatus(SUCCESS))\n", 0 );
|
||
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
//
|
||
// Internal Support Routine
|
||
//
|
||
|
||
RXSTATUS
|
||
RxSingleSyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for all reads and writes started via
|
||
RxRead/WriteSingleAsynch.
|
||
|
||
The completion routine has has the following responsibilities:
|
||
|
||
Copy the I/O status from the Irp to the Context, since the Irp
|
||
will no longer be accessible.
|
||
|
||
It sets the event in the Context parameter to signal the caller
|
||
that all of the asynch requests are done.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the file system device object.
|
||
|
||
Irp - Pointer to the Irp for this request. (This Irp will no longer
|
||
be accessible after this routine returns.)
|
||
|
||
Contxt - The context parameter which was specified in the call to
|
||
RxRead/WriteSingleAsynch.
|
||
|
||
Return Value:
|
||
|
||
Currently always returns RxStatus(SUCCESS).
|
||
|
||
--*/
|
||
|
||
{
|
||
PRDBSS_IO_CONTEXT Context = Contxt;
|
||
|
||
DebugTrace(+1, Dbg, "RxSingleSyncCompletionRoutine, Context = %08lx\n", Context );
|
||
|
||
KeSetEvent( &Context->Wait.SyncEvent, 0, FALSE );
|
||
|
||
DebugTrace(-1, Dbg, "RxSingleSyncCompletionRoutine -> RxStatus(MORE_PROCESSING_REQUIRED\n)", 0 );
|
||
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
|
||
return RxStatus(MORE_PROCESSING_REQUIRED);
|
||
}
|
||
|
||
|
||
//
|
||
// Internal Support Routine
|
||
//
|
||
|
||
RXSTATUS
|
||
RxSingleAsyncCompletionRoutine (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Contxt
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the completion routine for all reads and writes started via
|
||
RxRead/WriteSingleAsynch.
|
||
|
||
The completion routine has has the following responsibilities:
|
||
|
||
Copy the I/O status from the Irp to the Context, since the Irp
|
||
will no longer be accessible.
|
||
|
||
It sets the event in the Context parameter to signal the caller
|
||
that all of the asynch requests are done.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the file system device object.
|
||
|
||
Irp - Pointer to the Irp for this request. (This Irp will no longer
|
||
be accessible after this routine returns.)
|
||
|
||
Contxt - The context parameter which was specified in the call to
|
||
RxRead/WriteSingleAsynch.
|
||
|
||
Return Value:
|
||
|
||
Currently always returns RxStatus(SUCCESS).
|
||
|
||
--*/
|
||
|
||
{
|
||
PRDBSS_IO_CONTEXT Context = Contxt;
|
||
|
||
DebugTrace(+1, Dbg, "RxSingleAsyncCompletionRoutine, Context = %08lx\n", Context );
|
||
|
||
//
|
||
// Fill in the information field correctedly if this worked.
|
||
//
|
||
|
||
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
||
|
||
Irp->IoStatus.Information = Context->Wait.Async.RequestedByteCount;
|
||
|
||
//
|
||
// Now if this wasn't PagingIo, set either the read or write bit.
|
||
//
|
||
|
||
if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
|
||
|
||
SetFlag( Context->Wait.Async.FileObject->Flags,
|
||
IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_READ ?
|
||
FO_FILE_FAST_IO_READ : FO_FILE_MODIFIED );
|
||
}
|
||
}
|
||
|
||
//
|
||
// If this was a special async write, decrement the count. Set the
|
||
// event if this was the final outstanding I/O for the file. We will
|
||
// also want to queue an APC to deal with any error conditionions.
|
||
//
|
||
|
||
if ((Context->Wait.Async.NonPagedFcb) &&
|
||
(ExInterlockedAddUlong( &Context->Wait.Async.NonPagedFcb->OutstandingAsyncWrites,
|
||
0xffffffff,
|
||
&RxStrucSupSpinLock ) == 1)) {
|
||
|
||
KeSetEvent( Context->Wait.Async.NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
|
||
}
|
||
|
||
//
|
||
// Now release the resource
|
||
//
|
||
|
||
if (Context->Wait.Async.Resource != NULL) {
|
||
|
||
ExReleaseResourceForThread( Context->Wait.Async.Resource,
|
||
Context->Wait.Async.ResourceThreadId );
|
||
}
|
||
|
||
//
|
||
// Mark the Irp pending
|
||
//
|
||
|
||
IoMarkIrpPending( Irp );
|
||
|
||
//
|
||
// and finally, free the context record.
|
||
//
|
||
|
||
ExFreePool( Context );
|
||
|
||
DebugTrace(-1, Dbg, "RxSingleAsyncCompletionRoutine -> RxStatus(MORE_PROCESSING_REQUIRED\n)", 0 );
|
||
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
|
||
return RxStatus(SUCCESS);
|
||
}
|
||
|
||
|
||
VOID
|
||
RxToggleMediaEjectDisable (
|
||
IN PRX_CONTEXT RxContext,
|
||
IN PVCB Vcb,
|
||
IN BOOLEAN PreventRemoval
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine either enables or disables the eject button on removable
|
||
media. Any error conditions are ignored.
|
||
|
||
Arguments:
|
||
|
||
Vcb - Descibes the volume to operate on
|
||
|
||
PreventRemoval - TRUE if we should disable the media eject button. FALSE
|
||
if we want to enable it.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP Irp;
|
||
KEVENT Event;
|
||
RXSTATUS Status;
|
||
IO_STATUS_BLOCK Iosb;
|
||
PREVENT_MEDIA_REMOVAL Prevent;
|
||
|
||
Prevent.PreventMediaRemoval = PreventRemoval;
|
||
|
||
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
||
|
||
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_MEDIA_REMOVAL,
|
||
Vcb->Vpb->RealDevice,
|
||
&Prevent,
|
||
sizeof(PREVENT_MEDIA_REMOVAL),
|
||
NULL,
|
||
0,
|
||
FALSE,
|
||
&Event,
|
||
&Iosb );
|
||
|
||
if ( Irp != NULL ) {
|
||
|
||
Status = IoCallDriver( Vcb->TargetDeviceObject, Irp );
|
||
|
||
if (Status == RxStatus(PENDING)) {
|
||
Status = KeWaitForSingleObject( &Event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL );
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifdef WE_WON_ON_APPEAL
|
||
|
||
|
||
RXSTATUS
|
||
RxLowLevelDblsReadWrite (
|
||
PRX_CONTEXT RxContext,
|
||
PIRP Irp,
|
||
PVCB Vcb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine passes on a non-cached read or write request to the
|
||
double space routines. The status is extracted from an exception
|
||
handler in case of error.
|
||
|
||
Arguments:
|
||
|
||
Vcb - Descibes the volume to operate on.
|
||
|
||
Irp - Supplies the parameters for the read/write operation.
|
||
|
||
Return Value:
|
||
|
||
The Status of the read or write operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PIO_STACK_LOCATION IrpSp;
|
||
ULONG BytesTransfered = 0;
|
||
RXSTATUS Status = RxStatus(SUCCESS);
|
||
|
||
IrpSp = IoGetNextIrpStackLocation( Irp );
|
||
|
||
try {
|
||
|
||
#ifdef DOUBLE_SPACE_WRITE
|
||
|
||
BytesTransfered = (IrpSp->MajorFunction == IRP_MJ_READ) ?
|
||
|
||
RxDblsReadData( RxContext,
|
||
Vcb->Dscb,
|
||
IrpSp->Parameters.Read.ByteOffset.LowPart,
|
||
MmGetSystemAddressForMdl( Irp->MdlAddress ),
|
||
IrpSp->Parameters.Read.Length )
|
||
:
|
||
|
||
RxDblsWriteData( RxContext,
|
||
Vcb->Dscb,
|
||
IrpSp->Parameters.Write.ByteOffset.LowPart,
|
||
MmGetSystemAddressForMdl( Irp->MdlAddress ),
|
||
IrpSp->Parameters.Write.Length );
|
||
|
||
#else
|
||
|
||
BytesTransfered =
|
||
|
||
RxDblsReadData( RxContext,
|
||
Vcb->Dscb,
|
||
IrpSp->Parameters.Read.ByteOffset.LowPart,
|
||
MmGetSystemAddressForMdl( Irp->MdlAddress ),
|
||
IrpSp->Parameters.Read.Length );
|
||
#endif // DOUBLE_SPACE_WRITE
|
||
|
||
} except(RxExceptionFilter( RxContext, GetExceptionInformation() )) {
|
||
|
||
Status = RxContext->ExceptionStatus;
|
||
RxContext->ExceptionStatus = 0;
|
||
}
|
||
|
||
//
|
||
// Load up the Status in the Irp
|
||
//
|
||
|
||
Irp->IoStatus.Status = Status;
|
||
Irp->IoStatus.Information = BytesTransfered;
|
||
|
||
//
|
||
// Update the IRP stack to point to the next location so that our
|
||
// completion routine will get called.
|
||
//
|
||
|
||
Irp->CurrentLocation--;
|
||
Irp->Tail.Overlay.CurrentStackLocation--;
|
||
|
||
if (Irp->CurrentLocation <= 0) {
|
||
|
||
KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, (ULONG) Irp, 0, 0, 0 );
|
||
}
|
||
|
||
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
|
||
|
||
return Status;
|
||
}
|
||
|
||
#endif // WE_WON_ON_APPEAL
|
||
|