mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2445 lines
63 KiB
2445 lines
63 KiB
/*++
|
|
|
|
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
|
|
|