|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
NtFastIo.c
Abstract:
This module implements NT fastio routines.
Author:
Joe Linn [JoeLinn] 9-Nov-1994
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_NTFASTIO)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxFastIoRead)
#pragma alloc_text(PAGE, RxFastIoWrite)
#pragma alloc_text(PAGE, RxFastIoCheckIfPossible)
#endif
//
// these declarations would be copied to fsrtl.h
//
BOOLEAN FsRtlCopyRead2 ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject, IN ULONG_PTR TopLevelIrpValue ); BOOLEAN FsRtlCopyWrite2 ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject, IN ULONG_PTR TopLevelIrpValue );
BOOLEAN RxFastIoRead ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++
Routine Description: Basic fastio read routine for the rdr
Arguments:
FileObject - FileOffset - Length - Wait - LockKey - Buffer - IoStatus - DeviceObject -
Return value:
TRUE if successful
Notes:
--*/
{ BOOLEAN ReturnValue;
RX_TOPLEVELIRP_CONTEXT TopLevelContext;
PAGED_CODE();
RxDbgTrace( +1, Dbg, ("RxFastIoRead\n") );
RxLog(( "FastRead %lx:%lx:%lx", FileObject, FileObject->FsContext, FileObject->FsContext2 )); RxLog(( "------>> %lx@%lx %lx", Length, FileOffset->LowPart, FileOffset->HighPart )); RxWmiLog( LOG, RxFastIoRead_1, LOGPTR( FileObject ) LOGPTR( FileObject->FsContext ) LOGPTR( FileObject->FsContext2 ) LOGULONG( Length ) LOGULONG( FileOffset->LowPart ) LOGULONG( FileOffset->HighPart ) );
ASSERT( RxIsThisTheTopLevelIrp( NULL ) );
RxInitializeTopLevelIrpContext( &TopLevelContext, ((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP), (PRDBSS_DEVICE_OBJECT)DeviceObject );
ReturnValue = FsRtlCopyRead2( FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject, (ULONG_PTR)(&TopLevelContext) );
RxDbgTrace( -1, Dbg, ("RxFastIoRead ReturnValue=%x\n", ReturnValue) );
if (ReturnValue) { RxLog(( "FastReadYes %lx ret %lx:%lx", FileObject->FsContext2, IoStatus->Status, IoStatus->Information )); RxWmiLog( LOG, RxFastIoRead_2, LOGPTR( FileObject->FsContext2 ) LOGULONG( IoStatus->Status ) LOGPTR( IoStatus->Information ) ); } else { RxLog(( "FastReadNo %lx", FileObject->FsContext2 )); RxWmiLog( LOG, RxFastIoRead_3, LOGPTR( FileObject->FsContext2 ) ); }
return ReturnValue; }
BOOLEAN RxFastIoWrite ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++
Routine Description:
Arguments:
Routine Description: Basic fastio write routine for the rdr
Arguments:
FileObject - FileOffset - Length - Wait - LockKey - Buffer - IoStatus - DeviceObject -
Return value:
TRUE if successful --*/ { BOOLEAN ReturnValue;
RX_TOPLEVELIRP_CONTEXT TopLevelContext;
PSRV_OPEN SrvOpen;
PAGED_CODE();
RxDbgTrace(+1, Dbg, ("RxFastIoWrite\n"));
SrvOpen = ((PFOBX)(FileObject->FsContext2))->SrvOpen; if (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_DONTUSE_WRITE_CACHING )) {
//
// if this flag is set, we have to treat this as an unbuffered Io....sigh.
//
RxDbgTrace( -1, Dbg, ("RxFastIoWrite DONTUSE_WRITE_CACHEING...failing\n") ); return FALSE; }
ASSERT( RxIsThisTheTopLevelIrp( NULL ) );
RxInitializeTopLevelIrpContext( &TopLevelContext, ((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP), (PRDBSS_DEVICE_OBJECT)DeviceObject );
ReturnValue = FsRtlCopyWrite2( FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject, (ULONG_PTR)(&TopLevelContext) );
RxDbgTrace( -1, Dbg, ("RxFastIoWrite ReturnValue=%x\n", ReturnValue) );
if (ReturnValue) { RxLog(( "FWY %lx OLP: %lx SLP: %lx IOSB %lx:%lx", FileObject->FsContext2, FileOffset->LowPart, SrvOpen->Fcb->Header.FileSize.LowPart, IoStatus->Status, IoStatus->Information )); RxWmiLog( LOG, RxFastIoWrite_1, LOGPTR( FileObject->FsContext2 ) LOGULONG( FileOffset->LowPart ) LOGULONG( SrvOpen->Fcb->Header.FileSize.LowPart ) LOGULONG( IoStatus->Status ) LOGPTR( IoStatus->Information ) ); } else { RxLog(( "FastWriteNo %lx", FileObject->FsContext2 )); RxWmiLog( LOG, RxFastIoWrite_2, LOGPTR( FileObject->FsContext2 ) ); }
return ReturnValue; }
BOOLEAN RxFastIoCheckIfPossible ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN BOOLEAN CheckForReadOperation, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject )
/*++
Routine Description:
This routine checks if fast i/o is possible for a read/write operation
Arguments:
FileObject - Supplies the file object used in the query
FileOffset - Supplies the starting byte offset for the read/write operation
Length - Supplies the length, in bytes, of the read/write operation
Wait - Indicates if we can wait
LockKey - Supplies the lock key
CheckForReadOperation - Indicates if this is a check for a read or write operation
IoStatus - Receives the status of the operation if our return value is FastIoReturnError
Return Value:
BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs to take the long route.
--*/
{ PFCB Fcb; PFOBX Fobx; PSRV_OPEN SrvOpen; PCHAR FailureReason = NULL;
LARGE_INTEGER LargeLength;
PAGED_CODE();
RxDecodeFileObject( FileObject, &Fcb, &Fobx ); SrvOpen = Fobx->SrvOpen;
if (NodeType( Fcb ) != RDBSS_NTC_STORAGE_TYPE_FILE) { FailureReason = "notfile"; } else if (FileObject->DeletePending) { FailureReason = "delpend"; } else if (Fcb->NonPaged->OutstandingAsyncWrites != 0) { FailureReason = "asynW"; } else if (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED )) { FailureReason = "srvopen orphaned"; } else if (FlagOn( Fcb->FcbState, FCB_STATE_ORPHANED )) { FailureReason = "orphaned"; } else if (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING )) { FailureReason = "buf state change"; } else if (FlagOn( SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED | SRVOPEN_FLAG_FILE_DELETED)) { FailureReason = "ren/del"; } else {
//
// Ensure that all pending buffering state change requests are processed
// before letting the operation through.
//
FsRtlEnterFileSystem(); RxProcessChangeBufferingStateRequestsForSrvOpen( SrvOpen ); FsRtlExitFileSystem(); LargeLength.QuadPart = Length; //
// Based on whether this is a read or write operation we call
// fsrtl check for read/write
//
if (CheckForReadOperation) { if (!FlagOn( Fcb->FcbState, FCB_STATE_READCACHING_ENABLED )) { FailureReason = "notreadC"; } else if (!FsRtlFastCheckLockForRead( &Fcb->FileLock, FileOffset, &LargeLength, LockKey, FileObject, PsGetCurrentProcess() )) { FailureReason = "readlock"; } } else { if (!FlagOn( Fcb->FcbState,FCB_STATE_WRITECACHING_ENABLED )) { FailureReason = "notwriteC"; } else if (!FsRtlFastCheckLockForWrite( &Fcb->FileLock, FileOffset, &LargeLength, LockKey, FileObject, PsGetCurrentProcess() )) { FailureReason = "writelock"; } } }
if (FailureReason) { RxLog(( "CheckFast fail %lx %s", FileObject, FailureReason )); RxWmiLog( LOG, RxFastIoCheckIfPossible, LOGPTR( FileObject ) LOGARSTR( FailureReason ) ); return FALSE; } else { return TRUE; } }
BOOLEAN RxFastIoDeviceControl ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, IN ULONG IoControlCode, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++
Routine Description:
This routine is for the fast device control call.
Arguments:
FileObject - Supplies the file object used in this operation
Wait - Indicates if we are allowed to wait for the information
InputBuffer - Supplies the input buffer
InputBufferLength - the length of the input buffer
OutputBuffer - the output buffer
OutputBufferLength - the length of the output buffer
IoControlCode - the IO control code
IoStatus - Receives the final status of the operation
DeviceObject - the associated device object
Return Value:
BOOLEAN - TRUE if the operation succeeded and FALSE if the caller needs to take the long route.
Notes:
The following IO control requests are handled in the first path
IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER
InputBuffer - pointer to the other file object
InputBufferLength - length in bytes of a pointer.
OutputBuffer - not used
OutputBufferLength - not used
IoStatus --
IoStatus.Status set to STATUS_SUCCESS if both the file objects are on the same server, otherwise set to STATUS_NOT_SAME_DEVICE
This is a kernel mode interface only.
--*/ { PFCB Fcb; BOOLEAN FastIoSucceeded;
switch (IoControlCode) { case IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER: FastIoSucceeded = TRUE;
try { if (InputBufferLength == sizeof( HANDLE )) { PFCB Fcb2; HANDLE File; PFILE_OBJECT FileObject2; NTSTATUS Status;
Fcb = (PFCB)FileObject->FsContext;
RtlCopyMemory( &File, InputBuffer, sizeof( HANDLE ) );
Status = ObReferenceObjectByHandle( File, FILE_ANY_ACCESS, *IoFileObjectType, UserMode, &FileObject2, NULL );
if ((Status == STATUS_SUCCESS)) { if(FileObject2->DeviceObject == DeviceObject) { Fcb2 = (PFCB)FileObject2->FsContext;
if ((Fcb2 != NULL) && (NodeTypeIsFcb( Fcb2 ))) {
if (Fcb->NetRoot->SrvCall == Fcb2->NetRoot->SrvCall) { IoStatus->Status = STATUS_SUCCESS; } else { IoStatus->Status = STATUS_NOT_SAME_DEVICE; } } else { Status = STATUS_INVALID_PARAMETER; } } else { Status = STATUS_INVALID_PARAMETER; } ObDereferenceObject( FileObject2 ); } else { IoStatus->Status = STATUS_INVALID_PARAMETER; } } else { IoStatus->Status = STATUS_INVALID_PARAMETER; } } except( EXCEPTION_EXECUTE_HANDLER ) { //
// The I/O request was not handled successfully, abort the I/O request with
// the error status that we get back from the execption code
//
IoStatus->Status = STATUS_INVALID_PARAMETER; FastIoSucceeded = TRUE; } break;
case IOCTL_LMR_LWIO_PREIO: //
// This call allows the lwio user mode caller to preserve the wait IO model for
// callers that use the file handle as a synch object. Before each IO, the file
// object event must be cleared and after each IO the event must be set as per
// the IO manager semantics.
//
IoStatus->Status = STATUS_NOT_SUPPORTED; IoStatus->Information = 0; if (!FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO )) { Fcb = (PFCB)FileObject->FsContext; try { if ((Fcb != NULL) && (NodeType( Fcb ) == RDBSS_NTC_STORAGE_TYPE_FILE) && ((FileObject->SectionObjectPointer == NULL) || (FileObject->SectionObjectPointer->DataSectionObject == NULL))) { KeClearEvent( &FileObject->Event ); IoStatus->Status = STATUS_SUCCESS; IoStatus->Information = (ULONG_PTR) FileObject->LockOperation; } } except(EXCEPTION_EXECUTE_HANDLER) { IoStatus->Status = GetExceptionCode(); } } FastIoSucceeded = TRUE; break;
case IOCTL_LMR_LWIO_POSTIO: //
// This call allows the lwio user mode caller to complete the user mode IO for
// a given file handle. The caller specifies an IoStatus block that contains the
// user mode IO outcome.
//
IoStatus->Status = STATUS_NOT_SUPPORTED; IoStatus->Information = 0; if (!FlagOn( FileObject->Flags, FO_SYNCHRONOUS_IO ) && (InputBuffer != NULL) && (InputBufferLength == sizeof( *IoStatus ))) { PIO_STATUS_BLOCK Iosb = (PIO_STATUS_BLOCK)InputBuffer;
Fcb = (PFCB)FileObject->FsContext; try { if ((Fcb != NULL) && NodeType( Fcb ) == RDBSS_NTC_STORAGE_TYPE_FILE && ((FileObject->SectionObjectPointer == NULL) || (FileObject->SectionObjectPointer->DataSectionObject == NULL))) { KeSetEvent( &FileObject->Event, 0, FALSE ); IoStatus->Status = Iosb->Status; IoStatus->Information = Iosb->Information; } } except(EXCEPTION_EXECUTE_HANDLER) { IoStatus->Status = GetExceptionCode(); IoStatus->Information = 0; } } FastIoSucceeded = TRUE; break;
default: { Fcb = (PFCB)FileObject->FsContext; FastIoSucceeded = FALSE;
//
// Inform lwio rdr of this call
//
if ((Fcb != NULL) && NodeTypeIsFcb( Fcb ) && FlagOn( Fcb->FcbState, FCB_STATE_LWIO_ENABLED )) { PFAST_IO_DISPATCH FastIoDispatch = Fcb->MRxFastIoDispatch; if (FastIoDispatch && FastIoDispatch->FastIoDeviceControl && FastIoDispatch->FastIoDeviceControl( FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, IoControlCode, IoStatus, DeviceObject )) { FastIoSucceeded = TRUE; } } } }
return FastIoSucceeded; }
|