651 lines
18 KiB
C
651 lines
18 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
|