Leaked source code of windows server 2003
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

/*++
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;
}