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.
650 lines
19 KiB
650 lines
19 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|