/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    FastIo.c

Abstract:

    The Fast I/O path is used to avoid calling the file systems directly to
    do a cached read.  This module is only used if the file object indicates
    that caching is enabled (i.e., the private cache map is not null).

--*/

#include "FsRtlP.h"

#if DBG

typedef struct _FS_RTL_DEBUG_COUNTERS {

    ULONG AcquireFileExclusiveEx_Succeed;
    ULONG AcquireFileExclusiveEx_Fail;
    ULONG ReleaseFile;

    ULONG AcquireFileForModWriteEx_Succeed;
    ULONG AcquireFileForModWriteEx_Fail;
    ULONG ReleaseFileForModWrite;

    ULONG AcquireFileForCcFlushEx_Succeed;
    ULONG AcquireFileForCcFlushEx_Fail;
    ULONG ReleaseFileForCcFlush;

} FS_RTL_DEBUG_COUNTERS, *PFS_RTL_DEBUG_COUNTERS;

FS_RTL_DEBUG_COUNTERS gCounter = { 0, 0, 0,
                                   0, 0, 0,
                                   0, 0, 0 };

#endif

//
//  Trace level for the module
//

#define Dbg                              (0x04000000)

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FsRtlCopyRead)
#pragma alloc_text(PAGE, FsRtlCopyWrite)
#pragma alloc_text(PAGE, FsRtlMdlRead)
#pragma alloc_text(PAGE, FsRtlMdlReadDev)
#pragma alloc_text(PAGE, FsRtlPrepareMdlWrite)
#pragma alloc_text(PAGE, FsRtlPrepareMdlWriteDev)
#pragma alloc_text(PAGE, FsRtlMdlWriteComplete)
#pragma alloc_text(PAGE, FsRtlMdlWriteCompleteDev)
#pragma alloc_text(PAGE, FsRtlAcquireFileForCcFlush)
#pragma alloc_text(PAGE, FsRtlAcquireFileForCcFlushEx)
#pragma alloc_text(PAGE, FsRtlReleaseFileForCcFlush)
#pragma alloc_text(PAGE, FsRtlAcquireFileExclusive)
#pragma alloc_text(PAGE, FsRtlAcquireToCreateMappedSection)
#pragma alloc_text(PAGE, FsRtlAcquireFileExclusiveCommon)
#pragma alloc_text(PAGE, FsRtlReleaseFile)
#pragma alloc_text(PAGE, FsRtlGetFileSize)
#pragma alloc_text(PAGE, FsRtlSetFileSize)
#pragma alloc_text(PAGE, FsRtlIncrementCcFastReadNotPossible )
#pragma alloc_text(PAGE, FsRtlIncrementCcFastReadWait )

#endif


BOOLEAN
FsRtlCopyRead (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in BOOLEAN Wait,
    __in ULONG LockKey,
    __out_bcount(Length) PVOID Buffer,
    __out PIO_STATUS_BLOCK IoStatus,
    __in PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine does a fast cached read bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy read
    of a cached file object.  For a complete description of the arguments
    see CcCopyRead.

Arguments:

    FileObject - Pointer to the file object being read.

    FileOffset - Byte offset in file for desired data.

    Length - Length of desired data in bytes.

    Wait - FALSE if caller may not block, TRUE otherwise

    Buffer - Pointer to output buffer to which data should be copied.

    IoStatus - Pointer to standard I/O status block to receive the status
               for the transfer.

Return Value:

    FALSE - if Wait was supplied as FALSE and the data was not delivered, or
        if there is an I/O error.

    TRUE - if the data is being delivered

--*/

{
    PFSRTL_COMMON_FCB_HEADER Header;
    BOOLEAN Status = TRUE;
    ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES( FileOffset->QuadPart, Length );
    LARGE_INTEGER BeyondLastByte;
    PDEVICE_OBJECT targetVdo;

    PAGED_CODE();

    UNREFERENCED_PARAMETER (DeviceObject);

    //
    //  Special case a read of zero length
    //

    if (Length != 0) {

        //
        //  Check for overflow. Returning false here will re-route this request through the
        //  IRP based path, but this isn't performance critical.
        //

        if (MAXLONGLONG - FileOffset->QuadPart < (LONGLONG)Length) {

            IoStatus->Status = STATUS_INVALID_PARAMETER;
            IoStatus->Information = 0;

            return FALSE;
        }

        BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
        Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;

        //
        //  Enter the file system
        //

        FsRtlEnterFileSystem();

        //
        //  Increment performance counters and get the resource
        //

        if (Wait) {

            HOT_STATISTIC(CcFastReadWait) += 1;

            //
            //  Acquired shared on the common fcb header
            //

            (VOID)ExAcquireResourceSharedLite( Header->Resource, TRUE );

        } else {

            HOT_STATISTIC(CcFastReadNoWait) += 1;

            //
            //  Acquired shared on the common fcb header, and return if we
            //  don't get it
            //

            if (!ExAcquireResourceSharedLite( Header->Resource, FALSE )) {

                FsRtlExitFileSystem();

                CcFastReadResourceMiss += 1;

                return FALSE;
            }
        }

        //
        //  Now that the File is acquired shared, we can safely test if it
        //  is really cached and if we can do fast i/o and if not, then
        //  release the fcb and return.
        //

        if ((FileObject->PrivateCacheMap == NULL) ||
            (Header->IsFastIoPossible == FastIoIsNotPossible)) {

            ExReleaseResourceLite( Header->Resource );
            FsRtlExitFileSystem();

            HOT_STATISTIC(CcFastReadNotPossible) += 1;

            return FALSE;
        }

        //
        //  Check if fast I/O is questionable and if so then go ask the
        //  file system the answer
        //

        if (Header->IsFastIoPossible == FastIoIsQuestionable) {

            PFAST_IO_DISPATCH FastIoDispatch;

            ASSERT(!KeIsExecutingDpc());

            targetVdo = IoGetRelatedDeviceObject( FileObject );
            FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;


            //
            //  All file systems that set "Is Questionable" had better support
            // fast I/O
            //

            ASSERT(FastIoDispatch != NULL);
            ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);

            //
            //  Call the file system to check for fast I/O.  If the answer is
            //  anything other than GoForIt then we cannot take the fast I/O
            //  path.
            //

            if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
                                                        FileOffset,
                                                        Length,
                                                        Wait,
                                                        LockKey,
                                                        TRUE, // read operation
                                                        IoStatus,
                                                        targetVdo )) {

                //
                //  Fast I/O is not possible so release the Fcb and return.
                //

                ExReleaseResourceLite( Header->Resource );
                FsRtlExitFileSystem();

                HOT_STATISTIC(CcFastReadNotPossible) += 1;

                return FALSE;
            }
        }

        //
        //  Check for read past file size.
        //

        if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {

            if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
                IoStatus->Status = STATUS_END_OF_FILE;
                IoStatus->Information = 0;

                ExReleaseResourceLite( Header->Resource );
                FsRtlExitFileSystem();

                return TRUE;
            }

            Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
        }

        //
        //  We can do fast i/o so call the cc routine to do the work and then
        //  release the fcb when we've done.  If for whatever reason the
        //  copy read fails, then return FALSE to our caller.
        //
        //  Also mark this as the top level "Irp" so that lower file system
        //  levels will not attempt a pop-up
        //

        PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;

        try {

            if (Wait && ((BeyondLastByte.HighPart | Header->FileSize.HighPart) == 0)) {

                CcFastCopyRead( FileObject,
                                FileOffset->LowPart,
                                Length,
                                PageCount,
                                Buffer,
                                IoStatus );

                FileObject->Flags |= FO_FILE_FAST_IO_READ;

                ASSERT( (IoStatus->Status == STATUS_END_OF_FILE) ||
                        ((FileOffset->LowPart + IoStatus->Information) <= Header->FileSize.LowPart));

            } else {

                Status = CcCopyRead( FileObject,
                                     FileOffset,
                                     Length,
                                     Wait,
                                     Buffer,
                                     IoStatus );

                FileObject->Flags |= FO_FILE_FAST_IO_READ;

                ASSERT( !Status || (IoStatus->Status == STATUS_END_OF_FILE) ||
                        ((LONGLONG)(FileOffset->QuadPart + IoStatus->Information) <= Header->FileSize.QuadPart));
            }

            if (Status) {

                FileObject->CurrentByteOffset.QuadPart = FileOffset->QuadPart + IoStatus->Information;
            }

        } except( FsRtlIsNtstatusExpected(GetExceptionCode())
                                        ? EXCEPTION_EXECUTE_HANDLER
                                        : EXCEPTION_CONTINUE_SEARCH ) {

            Status = FALSE;
        }

        PsGetCurrentThread()->TopLevelIrp = 0;

        ExReleaseResourceLite( Header->Resource );
        FsRtlExitFileSystem();
        return Status;

    } else {

        //
        //  A zero length transfer was requested.
        //

        IoStatus->Status = STATUS_SUCCESS;
        IoStatus->Information = 0;

        return TRUE;
    }
}


BOOLEAN
FsRtlCopyWrite (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in BOOLEAN Wait,
    __in ULONG LockKey,
    __in_bcount(Length) PVOID Buffer,
    __out PIO_STATUS_BLOCK IoStatus,
    __in PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine does a fast cached write bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy write
    of a cached file object.  For a complete description of the arguments
    see CcCopyWrite.

Arguments:

    FileObject - Pointer to the file object being write.

    FileOffset - Byte offset in file for desired data.

    Length - Length of desired data in bytes.

    Wait - FALSE if caller may not block, TRUE otherwise

    Buffer - Pointer to output buffer to which data should be copied.

    IoStatus - Pointer to standard I/O status block to receive the status
               for the transfer.

Return Value:

    FALSE - if Wait was supplied as FALSE and the data was not delivered, or
        if there is an I/O error.

    TRUE - if the data is being delivered

--*/

{
    PFSRTL_COMMON_FCB_HEADER Header;
    BOOLEAN AcquiredShared = FALSE;
    BOOLEAN Status = TRUE;
    BOOLEAN FileSizeChanged = FALSE;
    BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
                                         (FileOffset->HighPart == -1));

    PAGED_CODE();
    UNREFERENCED_PARAMETER( DeviceObject );

    //
    //  Get a real pointer to the common fcb header
    //

    Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;

    //
    //  Do we need to verify the volume?  If so, we must go to the file
    //  system.  Also return FALSE if FileObject is write through, the
    //  File System must do that.
    //

    if (CcCanIWrite( FileObject, Length, Wait, FALSE ) &&
        !FlagOn(FileObject->Flags, FO_WRITE_THROUGH) &&
        CcCopyWriteWontFlush(FileObject, FileOffset, Length)) {

        //
        //  Assume our transfer will work
        //

        IoStatus->Status = STATUS_SUCCESS;
        IoStatus->Information = Length;

        //
        //  Special case the zero byte length
        //

        if (Length != 0) {

            //
            //  Enter the file system
            //

            FsRtlEnterFileSystem();

            //
            //  Split into separate paths for increased performance.  First
            //  we have the faster path which only supports Wait == TRUE and
            //  32 bits.  We will make an unsafe test on whether the fast path
            //  is ok, then just return FALSE later if we were wrong.  This
            //  should virtually never happen.
            //
            //  IMPORTANT NOTE: It is very important that any changes made to
            //                  this path also be applied to the 64-bit path
            //                  which is the else of this test!
            //

            if (Wait && (Header->AllocationSize.HighPart == 0)) {

                ULONG Offset, NewFileSize;
                ULONG OldFileSize = 0;
                ULONG OldValidDataLength = 0;
                LOGICAL Wrapped;

                //
                //  Make our best guess on whether we need the file exclusive
                //  or shared.  Note that we do not check FileOffset->HighPart
                //  until below.
                //

                NewFileSize = FileOffset->LowPart + Length;

                if (WriteToEndOfFile || (NewFileSize > Header->ValidDataLength.LowPart)) {

                    //
                    //  Acquired shared on the common fcb header
                    //

                    ExAcquireResourceExclusiveLite( Header->Resource, TRUE );

                } else {

                    //
                    //  Acquired shared on the common fcb header
                    //

                    ExAcquireResourceSharedLite( Header->Resource, TRUE );

                    AcquiredShared = TRUE;
                }

                //
                //  We have the fcb shared now check if we can do fast i/o
                //  and if the file space is allocated, and if not then
                //  release the fcb and return.
                //

                if (WriteToEndOfFile) {

                    Offset = Header->FileSize.LowPart;
                    NewFileSize = Header->FileSize.LowPart + Length;
                    Wrapped = NewFileSize < Header->FileSize.LowPart;

                } else {

                    Offset = FileOffset->LowPart;
                    NewFileSize = FileOffset->LowPart + Length;
                    Wrapped = (NewFileSize < FileOffset->LowPart) || (FileOffset->HighPart != 0);
                }

                //
                //  Now that the File is acquired shared, we can safely test
                //  if it is really cached and if we can do fast i/o and we
                //  do not have to extend. If not then release the fcb and
                //  return.
                //
                //  Get out if we have too much to zero.  This case is not important
                //  for performance, and a file system supporting sparseness may have
                //  a way to do this more efficiently.
                //

                if ((FileObject->PrivateCacheMap == NULL) ||
                    (Header->IsFastIoPossible == FastIoIsNotPossible) ||
                    (NewFileSize > Header->AllocationSize.LowPart) ||
                    (Offset >= (Header->ValidDataLength.LowPart + 0x2000)) ||
                    (Header->AllocationSize.HighPart != 0) || Wrapped) {

                    ExReleaseResourceLite( Header->Resource );
                    FsRtlExitFileSystem();

                    return FALSE;
                }

                //
                //  If we will be extending ValidDataLength, we will have to
                //  get the Fcb exclusive, and make sure that FastIo is still
                //  possible.  We should only execute this block of code very
                //  rarely, when the unsafe test for ValidDataLength failed
                //  above.
                //

                if (AcquiredShared && (NewFileSize > Header->ValidDataLength.LowPart)) {

                    ExReleaseResourceLite( Header->Resource );

                    ExAcquireResourceExclusiveLite( Header->Resource, TRUE );

                    //
                    // If writing to end of file, we must recalculate new size.
                    //

                    if (WriteToEndOfFile) {

                        Offset = Header->FileSize.LowPart;
                        NewFileSize = Header->FileSize.LowPart + Length;
                        Wrapped = NewFileSize < Header->FileSize.LowPart;
                    }

                    if ((FileObject->PrivateCacheMap == NULL) ||
                        (Header->IsFastIoPossible == FastIoIsNotPossible) ||
                        (NewFileSize > Header->AllocationSize.LowPart) ||
                        (Header->AllocationSize.HighPart != 0) || Wrapped) {

                        ExReleaseResourceLite( Header->Resource );
                        FsRtlExitFileSystem();

                        return FALSE;
                    }
                }

                //
                //  Check if fast I/O is questionable and if so then go ask
                //  the file system the answer
                //

                if (Header->IsFastIoPossible == FastIoIsQuestionable) {

                    PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
                    PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
                    IO_STATUS_BLOCK IoStatus;

                    //
                    //  All file system then set "Is Questionable" had better
                    //  support fast I/O
                    //

                    ASSERT(FastIoDispatch != NULL);
                    ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);

                    //
                    //  Call the file system to check for fast I/O.  If the
                    //  answer is anything other than GoForIt then we cannot
                    //  take the fast I/O path.
                    //

                    ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);

                    if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
                                                                FileOffset->QuadPart != (LONGLONG)-1 ?
                                                                  FileOffset : &Header->FileSize,
                                                                Length,
                                                                TRUE,
                                                                LockKey,
                                                                FALSE, // write operation
                                                                &IoStatus,
                                                                targetVdo )) {

                        //
                        //  Fast I/O is not possible so release the Fcb and
                        //  return.
                        //

                        ExReleaseResourceLite( Header->Resource );
                        FsRtlExitFileSystem();

                        return FALSE;
                    }
                }

                //
                //  Now see if we will change FileSize.  We have to do it now
                //  so that our reads are not nooped.
                //

                if (NewFileSize > Header->FileSize.LowPart) {

                    FileSizeChanged = TRUE;
                    OldFileSize = Header->FileSize.LowPart;
                    OldValidDataLength = Header->ValidDataLength.LowPart;
                    Header->FileSize.LowPart = NewFileSize;
                }

                //
                //  We can do fast i/o so call the cc routine to do the work
                //  and then release the fcb when we've done.  If for whatever
                //  reason the copy write fails, then return FALSE to our
                //  caller.
                //
                //  Also mark this as the top level "Irp" so that lower file
                //  system levels will not attempt a pop-up
                //

                PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;

                try {

                    //
                    //  See if we have to do some zeroing
                    //

                    if (Offset > Header->ValidDataLength.LowPart) {

                        LARGE_INTEGER ZeroEnd;

                        ZeroEnd.LowPart = Offset;
                        ZeroEnd.HighPart = 0;

                        CcZeroData( FileObject,
                                    &Header->ValidDataLength,
                                    &ZeroEnd,
                                    TRUE );
                    }

                    CcFastCopyWrite( FileObject,
                                     Offset,
                                     Length,
                                     Buffer );

                } except( FsRtlIsNtstatusExpected(GetExceptionCode())
                                                ? EXCEPTION_EXECUTE_HANDLER
                                                : EXCEPTION_CONTINUE_SEARCH ) {

                    Status = FALSE;
                }

                PsGetCurrentThread()->TopLevelIrp = 0;

                //
                //  If we succeeded, see if we have to update FileSize or
                //  ValidDataLength.
                //

                if (Status) {

                    //
                    //  In the case of ValidDataLength, we really have to
                    //  check again since we did not do this when we acquired
                    //  the resource exclusive.
                    //

                    if (NewFileSize > Header->ValidDataLength.LowPart) {

                        Header->ValidDataLength.LowPart = NewFileSize;
                    }

                    //
                    //  Set this handle as having modified the file
                    //

                    FileObject->Flags |= FO_FILE_MODIFIED;

                    if (FileSizeChanged) {

                        CcGetFileSizePointer(FileObject)->LowPart = NewFileSize;

                        FileObject->Flags |= FO_FILE_SIZE_CHANGED;
                    }

                    //
                    //  Also update the file position pointer
                    //

                    FileObject->CurrentByteOffset.LowPart = Offset + Length;
                    FileObject->CurrentByteOffset.HighPart = 0;

                //
                //  If we did not succeed, then we must restore the original
                //  FileSize while holding the PagingIoResource exclusive if
                //  it exists.
                //

                } else if (FileSizeChanged) {

                    if ( Header->PagingIoResource != NULL ) {

                        (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
                        Header->FileSize.LowPart = OldFileSize;
                        Header->ValidDataLength.LowPart = OldValidDataLength;
                        ExReleaseResourceLite( Header->PagingIoResource );

                    } else {

                        Header->FileSize.LowPart = OldFileSize;
                        Header->ValidDataLength.LowPart = OldValidDataLength;
                    }
                }

            //
            //  Here is the 64-bit or no-wait path.
            //

            } else {

                LARGE_INTEGER Offset, NewFileSize;
                LARGE_INTEGER OldFileSize = {0};
                LARGE_INTEGER OldValidDataLength = {0};

                ASSERT(!KeIsExecutingDpc());

                //
                //  Make our best guess on whether we need the file exclusive
                //  or shared.
                //

                NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;

                if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {

                    //
                    //  Acquired shared on the common fcb header, and return
                    //  if we don't get it.
                    //

                    if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {

                        FsRtlExitFileSystem();

                        return FALSE;
                    }

                } else {

                    //
                    //  Acquired shared on the common fcb header, and return
                    //  if we don't get it.
                    //

                    if (!ExAcquireResourceSharedLite( Header->Resource, Wait )) {

                        FsRtlExitFileSystem();

                        return FALSE;
                    }

                    AcquiredShared = TRUE;
                }


                //
                //  We have the fcb shared now check if we can do fast i/o
                //  and if the file space is allocated, and if not then
                //  release the fcb and return.
                //

                if (WriteToEndOfFile) {

                    Offset = Header->FileSize;
                    NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;

                } else {

                    Offset = *FileOffset;
                    NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
                }

                //
                //  Now that the File is acquired shared, we can safely test
                //  if it is really cached and if we can do fast i/o and we
                //  do not have to extend. If not then release the fcb and
                //  return.
                //
                //  Get out if we are about to zero too much as well, as commented above.
                //  Likewise, for NewFileSizes that exceed MAXLONGLONG.
                //

                if ((FileObject->PrivateCacheMap == NULL) ||
                    (Header->IsFastIoPossible == FastIoIsNotPossible) ||
                      (Offset.QuadPart >= (Header->ValidDataLength.QuadPart + 0x2000)) ||
                      (MAXLONGLONG - Offset.QuadPart < (LONGLONG)Length) ||
                      (NewFileSize.QuadPart > Header->AllocationSize.QuadPart) ) {

                    ExReleaseResourceLite( Header->Resource );
                    FsRtlExitFileSystem();

                    return FALSE;
                }

                //
                //  If we will be extending ValidDataLength, we will have to
                //  get the Fcb exclusive, and make sure that FastIo is still
                //  possible.  We should only execute this block of code very
                //  rarely, when the unsafe test for ValidDataLength failed
                //  above.
                //

                if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) {

                    ExReleaseResourceLite( Header->Resource );

                    if (!ExAcquireResourceExclusiveLite( Header->Resource, Wait )) {

                        FsRtlExitFileSystem();

                        return FALSE;
                    }

                    //
                    // If writing to end of file, we must recalculate new size.
                    //

                    if (WriteToEndOfFile) {

                        Offset = Header->FileSize;
                        NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
                    }

                    if ((FileObject->PrivateCacheMap == NULL) ||
                        (Header->IsFastIoPossible == FastIoIsNotPossible) ||
                        ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {

                        ExReleaseResourceLite( Header->Resource );
                        FsRtlExitFileSystem();

                        return FALSE;
                    }
                }

                //
                //  Check if fast I/O is questionable and if so then go ask
                //  the file system the answer
                //

                if (Header->IsFastIoPossible == FastIoIsQuestionable) {

                    PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
                    PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;
                    IO_STATUS_BLOCK IoStatus;

                    //
                    //  All file system then set "Is Questionable" had better
                    //  support fast I/O
                    //

                    ASSERT(FastIoDispatch != NULL);
                    ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);

                    //
                    //  Call the file system to check for fast I/O.  If the
                    //  answer is anything other than GoForIt then we cannot
                    //  take the fast I/O path.
                    //

                    ASSERT(FILE_WRITE_TO_END_OF_FILE == 0xffffffff);

                    if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
                                                                FileOffset->QuadPart != (LONGLONG)-1 ?
                                                                  FileOffset : &Header->FileSize,
                                                                Length,
                                                                Wait,
                                                                LockKey,
                                                                FALSE, // write operation
                                                                &IoStatus,
                                                                targetVdo )) {

                        //
                        //  Fast I/O is not possible so release the Fcb and
                        //  return.
                        //

                        ExReleaseResourceLite( Header->Resource );
                        FsRtlExitFileSystem();

                        return FALSE;
                    }
                }

                //
                //  Now see if we will change FileSize.  We have to do it now
                //  so that our reads are not nooped.
                //

                if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) {

                    FileSizeChanged = TRUE;
                    OldFileSize = Header->FileSize;
                    OldValidDataLength = Header->ValidDataLength;

                    //
                    //  Deal with an extremely rare pathological case here the
                    //  file size wraps.
                    //

                    if ( (Header->FileSize.HighPart != NewFileSize.HighPart) &&
                         (Header->PagingIoResource != NULL) ) {

                        (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
                        Header->FileSize = NewFileSize;
                        ExReleaseResourceLite( Header->PagingIoResource );

                    } else {

                        Header->FileSize = NewFileSize;
                    }
                }

                //
                //  We can do fast i/o so call the cc routine to do the work
                //  and then release the fcb when we've done.  If for whatever
                //  reason the copy write fails, then return FALSE to our
                //  caller.
                //
                //  Also mark this as the top level "Irp" so that lower file
                //  system levels will not attempt a pop-up
                //

                PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;

                try {

                    //
                    //  See if we have to do some zeroing
                    //

                    if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {

                        Status = CcZeroData( FileObject,
                                             &Header->ValidDataLength,
                                             &Offset,
                                             Wait );
                    }

                    if (Status) {

                        Status = CcCopyWrite( FileObject,
                                              &Offset,
                                              Length,
                                              Wait,
                                              Buffer );
                    }

                } except( FsRtlIsNtstatusExpected(GetExceptionCode())
                                                ? EXCEPTION_EXECUTE_HANDLER
                                                : EXCEPTION_CONTINUE_SEARCH ) {

                    Status = FALSE;
                }

                PsGetCurrentThread()->TopLevelIrp = 0;

                //
                //  If we succeeded, see if we have to update FileSize or
                //  ValidDataLength.
                //

                if (Status) {

                    //
                    //  In the case of ValidDataLength, we really have to
                    //  check again since we did not do this when we acquired
                    //  the resource exclusive.
                    //

                    if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) {

                        //
                        //  Deal with an extremely rare pathological case here
                        //  the ValidDataLength wraps.
                        //

                        if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) &&
                             (Header->PagingIoResource != NULL) ) {

                            (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
                            Header->ValidDataLength = NewFileSize;
                            ExReleaseResourceLite( Header->PagingIoResource );

                        } else {

                            Header->ValidDataLength = NewFileSize;
                        }
                    }

                    //
                    //  Set this handle as having modified the file
                    //

                    FileObject->Flags |= FO_FILE_MODIFIED;

                    if (FileSizeChanged) {

                        *CcGetFileSizePointer(FileObject) = NewFileSize;

                        FileObject->Flags |= FO_FILE_SIZE_CHANGED;
                    }

                    //
                    //  Also update the current file position pointer
                    //

                    FileObject->CurrentByteOffset.QuadPart = Offset.QuadPart + Length;

                //
                // If we did not succeed, then we must restore the original
                // FileSize while holding the PagingIoResource exclusive if
                // it exists.
                //

                } else if (FileSizeChanged) {

                    if ( Header->PagingIoResource != NULL ) {

                        (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
                        Header->FileSize = OldFileSize;
                        Header->ValidDataLength = OldValidDataLength;
                        ExReleaseResourceLite( Header->PagingIoResource );

                    } else {

                        Header->FileSize = OldFileSize;
                        Header->ValidDataLength = OldValidDataLength;
                    }
                }

            }

            ExReleaseResourceLite( Header->Resource );
            FsRtlExitFileSystem();

            return Status;

        } else {

            //
            //  A zero length transfer was requested.
            //

            return TRUE;
        }

    } else {

        //
        // The volume must be verified or the file is write through.
        //

        return FALSE;
    }
}


BOOLEAN
FsRtlMdlReadDev (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG LockKey,
    __out PMDL *MdlChain,
    __out PIO_STATUS_BLOCK IoStatus,
    __in PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine does a fast cached mdl read bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy read
    of a cached file object.  For a complete description of the arguments
    see CcMdlRead.

Arguments:

    FileObject - Pointer to the file object being read.

    FileOffset - Byte offset in file for desired data.

    Length - Length of desired data in bytes.

    MdlChain - On output it returns a pointer to an MDL chain describing
        the desired data.

    IoStatus - Pointer to standard I/O status block to receive the status
               for the transfer.

    DeviceObject - Supplies DeviceObject for callee.

Return Value:

    FALSE - if the data was not delivered, or if there is an I/O error.

    TRUE - if the data is being delivered

--*/

{
    PFSRTL_COMMON_FCB_HEADER Header;
    BOOLEAN Status = TRUE;
    LARGE_INTEGER BeyondLastByte;

    PAGED_CODE();

    UNREFERENCED_PARAMETER (DeviceObject);

    //
    //  Special case a read of zero length
    //

    if (Length == 0) {

        IoStatus->Status = STATUS_SUCCESS;
        IoStatus->Information = 0;

        return TRUE;
    }

    //
    //  Overflows should've been handled by caller.
    //

    ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length);


    //
    //  Get a real pointer to the common fcb header
    //

    BeyondLastByte.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
    Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;

    //
    //  Enter the file system
    //

    FsRtlEnterFileSystem();

    CcFastMdlReadWait += 1;

    //
    //  Acquired shared on the common fcb header
    //

    (VOID)ExAcquireResourceSharedLite( Header->Resource, TRUE );

    //
    //  Now that the File is acquired shared, we can safely test if it is
    //  really cached and if we can do fast i/o and if not
    //  then release the fcb and return.
    //

    if ((FileObject->PrivateCacheMap == NULL) ||
        (Header->IsFastIoPossible == FastIoIsNotPossible)) {

        ExReleaseResourceLite( Header->Resource );
        FsRtlExitFileSystem();

        CcFastMdlReadNotPossible += 1;

        return FALSE;
    }

    //
    //  Check if fast I/O is questionable and if so then go ask the file system
    //  the answer
    //

    if (Header->IsFastIoPossible == FastIoIsQuestionable) {

        PDEVICE_OBJECT targetVdo = IoGetRelatedDeviceObject( FileObject );
        PFAST_IO_DISPATCH FastIoDispatch = targetVdo->DriverObject->FastIoDispatch;

        ASSERT(!KeIsExecutingDpc());

        //
        //  All file system then set "Is Questionable" had better support fast I/O
        //

        ASSERT(FastIoDispatch != NULL);
        ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);

        //
        //  Call the file system to check for fast I/O.  If the answer is anything
        //  other than GoForIt then we cannot take the fast I/O path.
        //

        if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
                                                    FileOffset,
                                                    Length,
                                                    TRUE,
                                                    LockKey,
                                                    TRUE, // read operation
                                                    IoStatus,
                                                    targetVdo )) {

            //
            //  Fast I/O is not possible so release the Fcb and return.
            //

            ExReleaseResourceLite( Header->Resource );
            FsRtlExitFileSystem();

            CcFastMdlReadNotPossible += 1;

            return FALSE;
        }
    }

    //
    //  Check for read past file size.
    //

    if ( BeyondLastByte.QuadPart > Header->FileSize.QuadPart ) {

        if ( FileOffset->QuadPart >= Header->FileSize.QuadPart ) {
            IoStatus->Status = STATUS_END_OF_FILE;
            IoStatus->Information = 0;

            ExReleaseResourceLite( Header->Resource );
            FsRtlExitFileSystem();

            return TRUE;
        }

        Length = (ULONG)( Header->FileSize.QuadPart - FileOffset->QuadPart );
    }

    //
    //  We can do fast i/o so call the cc routine to do the work and then
    //  release the fcb when we've done.  If for whatever reason the
    //  mdl read fails, then return FALSE to our caller.
    //
    //
    //  Also mark this as the top level "Irp" so that lower file system levels
    //  will not attempt a pop-up
    //

    PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;

    try {

        CcMdlRead( FileObject, FileOffset, Length, MdlChain, IoStatus );

        FileObject->Flags |= FO_FILE_FAST_IO_READ;

    } except( FsRtlIsNtstatusExpected(GetExceptionCode())
                                   ? EXCEPTION_EXECUTE_HANDLER
                                   : EXCEPTION_CONTINUE_SEARCH ) {

        Status = FALSE;
    }

    PsGetCurrentThread()->TopLevelIrp = 0;

    ExReleaseResourceLite( Header->Resource );
    FsRtlExitFileSystem();

    return Status;
}


//
//  The old routine will either dispatch or call FsRtlMdlReadDev
//

BOOLEAN
FsRtlMdlRead (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG LockKey,
    __out PMDL *MdlChain,
    __out PIO_STATUS_BLOCK IoStatus
    )

/*++

Routine Description:

    This routine does a fast cached mdl read bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy read
    of a cached file object.  For a complete description of the arguments
    see CcMdlRead.

Arguments:

    FileObject - Pointer to the file object being read.

    FileOffset - Byte offset in file for desired data.

    Length - Length of desired data in bytes.

    MdlChain - On output it returns a pointer to an MDL chain describing
        the desired data.

    IoStatus - Pointer to standard I/O status block to receive the status
               for the transfer.

Return Value:

    FALSE - if the data was not delivered, or if there is an I/O error.

    TRUE - if the data is being delivered

--*/

{
    PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
    PFAST_IO_DISPATCH FastIoDispatch;

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;

    //
    //  See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
    //

    if ((FastIoDispatch != NULL) &&
        (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead)) &&
        (FastIoDispatch->MdlRead != NULL)) {

        return FastIoDispatch->MdlRead( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );

    } else {

        //
        //  Get the DeviceObject for the volume.  If that DeviceObject is different, and
        //  it specifies the FastIo routine, then we have to return FALSE here and cause
        //  an Irp to get generated.
        //

        VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
        if ((VolumeDeviceObject != DeviceObject) &&
            (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
            (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead)) &&
            (FastIoDispatch->MdlRead != NULL)) {

            return FALSE;

        //
        //  Otherwise, call the default routine.
        //

        } else {

            return FsRtlMdlReadDev( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );
        }
    }
}


//
//  The old routine will either dispatch or call FsRtlMdlReadCompleteDev
//

BOOLEAN
FsRtlMdlReadComplete (
    __in PFILE_OBJECT FileObject,
    __in PMDL MdlChain
    )

/*++

Routine Description:

    This routine does a fast cached mdl read bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy read
    of a cached file object.

Arguments:

    FileObject - Pointer to the file object being read.

    MdlChain - Supplies a pointer to an MDL chain returned from CcMdlRead.

Return Value:

    None

--*/

{
    PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
    PFAST_IO_DISPATCH FastIoDispatch;

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;

    //
    //  See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
    //

    if ((FastIoDispatch != NULL) &&
        (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete)) &&
        (FastIoDispatch->MdlReadComplete != NULL)) {

        return FastIoDispatch->MdlReadComplete( FileObject, MdlChain, DeviceObject );

    } else {

        //
        //  Get the DeviceObject for the volume.  If that DeviceObject is different, and
        //  it specifies the FastIo routine, then we have to return FALSE here and cause
        //  an Irp to get generated.
        //

        VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
        if ((VolumeDeviceObject != DeviceObject) &&
            (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
            (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete)) &&
            (FastIoDispatch->MdlReadComplete != NULL)) {

            return FALSE;

        //
        //  Otherwise, call the default routine.
        //

        } else {

            return FsRtlMdlReadCompleteDev( FileObject, MdlChain, DeviceObject );
        }
    }
}


BOOLEAN
FsRtlMdlReadCompleteDev (
    __in PFILE_OBJECT FileObject,
    __in PMDL MdlChain,
    __in PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine does a fast cached mdl read bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy read
    of a cached file object.

Arguments:

    FileObject - Pointer to the file object being read.

    MdlChain - Supplies a pointer to an MDL chain returned from CcMdlRead.

    DeviceObject - Supplies the DeviceObject for the callee.

Return Value:

    None

--*/


{
    UNREFERENCED_PARAMETER (DeviceObject);

    CcMdlReadComplete2( FileObject, MdlChain );
    return TRUE;
}


BOOLEAN
FsRtlPrepareMdlWriteDev (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG LockKey,
    __out PMDL *MdlChain,
    __out PIO_STATUS_BLOCK IoStatus,
    __in PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine does a fast cached mdl read bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy read
    of a cached file object.  For a complete description of the arguments
    see CcMdlRead.

Arguments:

    FileObject - Pointer to the file object being read.

    FileOffset - Byte offset in file for desired data.

    Length - Length of desired data in bytes.

    MdlChain - On output it returns a pointer to an MDL chain describing
        the desired data.

    IoStatus - Pointer to standard I/O status block to receive the status
               for the transfer.

    DeviceObject - Supplies the DeviceObject for the callee.

Return Value:

    FALSE - if the data was not written, or if there is an I/O error.

    TRUE - if the data is being written

--*/

{
    PFSRTL_COMMON_FCB_HEADER Header;
    LARGE_INTEGER Offset, NewFileSize;
    LARGE_INTEGER OldFileSize = {0};
    LARGE_INTEGER OldValidDataLength = {0};
    BOOLEAN Status = TRUE;
    BOOLEAN AcquiredShared = FALSE;
    BOOLEAN FileSizeChanged = FALSE;
    BOOLEAN WriteToEndOfFile = (BOOLEAN)((FileOffset->LowPart == FILE_WRITE_TO_END_OF_FILE) &&
                                         (FileOffset->HighPart == -1));

    PAGED_CODE();

    UNREFERENCED_PARAMETER (DeviceObject);

    //
    //  Call CcCanIWrite.  Also return FALSE if FileObject is write through,
    //  the File System must do that.
    //

    if ( !CcCanIWrite( FileObject, Length, TRUE, FALSE ) ||
         FlagOn( FileObject->Flags, FO_WRITE_THROUGH )) {

        return FALSE;
    }

    //
    //  Assume our transfer will work
    //

    IoStatus->Status = STATUS_SUCCESS;

    //
    //  Special case the zero byte length
    //

    if (Length == 0) {

        return TRUE;
    }

    //
    //  Get a real pointer to the common fcb header
    //

    Header = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext;

    //
    //  Enter the file system
    //

    FsRtlEnterFileSystem();

    //
    //  Make our best guess on whether we need the file exclusive or
    //  shared.
    //

    NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;

    if (WriteToEndOfFile || (NewFileSize.QuadPart > Header->ValidDataLength.QuadPart)) {

        //
        //  Acquired exclusive on the common fcb header, and return if we don't
        //  get it.
        //

        ExAcquireResourceExclusiveLite( Header->Resource, TRUE );

    } else {

        //
        //  Acquired shared on the common fcb header, and return if we don't
        //  get it.
        //

        ExAcquireResourceSharedLite( Header->Resource, TRUE );

        AcquiredShared = TRUE;
    }


    //
    //  We have the fcb shared now check if we can do fast i/o  and if the file
    //  space is allocated, and if not then release the fcb and return.
    //

    if (WriteToEndOfFile) {

        Offset = Header->FileSize;
        NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;

    } else {

        Offset = *FileOffset;
        NewFileSize.QuadPart = FileOffset->QuadPart + (LONGLONG)Length;
    }

    //
    //  Now that the File is acquired shared, we can safely test if it is
    //  really cached and if we can do fast i/o and we do not have to extend.
    //  If not then release the fcb and return.
    //

    if ((FileObject->PrivateCacheMap == NULL) ||
        (Header->IsFastIoPossible == FastIoIsNotPossible) ||
        (MAXLONGLONG - Offset.QuadPart < (LONGLONG)Length) ||
        ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart ) ) {

        ExReleaseResourceLite( Header->Resource );
        FsRtlExitFileSystem();

        return FALSE;
    }

    //
    //  If we will be extending ValidDataLength, we will have to get the
    //  Fcb exclusive, and make sure that FastIo is still possible.
    //

    if (AcquiredShared && ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart )) {

        ExReleaseResourceLite( Header->Resource );

        ExAcquireResourceExclusiveLite( Header->Resource, TRUE );

        AcquiredShared = FALSE;

        //
        //  If writing to end of file, we must recalculate new size.
        //

        if (WriteToEndOfFile) {

            Offset = Header->FileSize;
            NewFileSize.QuadPart = Header->FileSize.QuadPart + (LONGLONG)Length;
        }

        if ((FileObject->PrivateCacheMap == NULL) ||
            (Header->IsFastIoPossible == FastIoIsNotPossible) ||
            ( NewFileSize.QuadPart > Header->AllocationSize.QuadPart )) {

            ExReleaseResourceLite( Header->Resource );
            FsRtlExitFileSystem();

            return FALSE;
        }
    }

    //
    //  Check if fast I/O is questionable and if so then go ask the file system
    //  the answer
    //

    if (Header->IsFastIoPossible == FastIoIsQuestionable) {

        PFAST_IO_DISPATCH FastIoDispatch = IoGetRelatedDeviceObject( FileObject )->DriverObject->FastIoDispatch;

        //
        //  All file system then set "Is Questionable" had better support fast I/O
        //

        ASSERT(FastIoDispatch != NULL);
        ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL);

        //
        //  Call the file system to check for fast I/O.  If the answer is anything
        //  other than GoForIt then we cannot take the fast I/O path.
        //

        if (!FastIoDispatch->FastIoCheckIfPossible( FileObject,
                                                    FileOffset,
                                                    Length,
                                                    TRUE,
                                                    LockKey,
                                                    FALSE, // write operation
                                                    IoStatus,
                                                    IoGetRelatedDeviceObject( FileObject ) )) {

            //
            //  Fast I/O is not possible so release the Fcb and return.
            //

            ExReleaseResourceLite( Header->Resource );
            FsRtlExitFileSystem();

            return FALSE;
        }
    }

    //
    // Now see if we will change FileSize.  We have to do it now so that our
    // reads are not nooped.
    //

    if ( NewFileSize.QuadPart > Header->FileSize.QuadPart ) {

        FileSizeChanged = TRUE;
        OldFileSize = Header->FileSize;
        OldValidDataLength = Header->ValidDataLength;

        //
        //  Deal with an extremely rare pathological case here the file
        //  size wraps.
        //

        if ( (Header->FileSize.HighPart != NewFileSize.HighPart) &&
             (Header->PagingIoResource != NULL) ) {

            (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
            Header->FileSize = NewFileSize;
            ExReleaseResourceLite( Header->PagingIoResource );

        } else {

            Header->FileSize = NewFileSize;
        }
    }

    //
    //  We can do fast i/o so call the cc routine to do the work and then
    //  release the fcb when we've done.  If for whatever reason the
    //  copy write fails, then return FALSE to our caller.
    //
    //
    //  Also mark this as the top level "Irp" so that lower file system levels
    //  will not attempt a pop-up
    //

    PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP;

    try {

        //
        //  See if we have to do some zeroing
        //

        if ( Offset.QuadPart > Header->ValidDataLength.QuadPart ) {

            Status = CcZeroData( FileObject,
                                 &Header->ValidDataLength,
                                 &Offset,
                                 TRUE );
        }

        if (Status) {

            CcPrepareMdlWrite( FileObject, &Offset, Length, MdlChain, IoStatus );
        }

    } except( FsRtlIsNtstatusExpected(GetExceptionCode())
                                    ? EXCEPTION_EXECUTE_HANDLER
                                    : EXCEPTION_CONTINUE_SEARCH ) {

        Status = FALSE;
    }

    PsGetCurrentThread()->TopLevelIrp = 0;

    //
    //  If we succeeded, see if we have to update FileSize or ValidDataLength.
    //

    if (Status) {

        //
        // In the case of ValidDataLength, we really have to check again
        // since we did not do this when we acquired the resource exclusive.
        //

        if ( NewFileSize.QuadPart > Header->ValidDataLength.QuadPart ) {

            //
            //  Deal with an extremely rare pathological case here the
            //  ValidDataLength wraps.
            //

            if ( (Header->ValidDataLength.HighPart != NewFileSize.HighPart) &&
                 (Header->PagingIoResource != NULL) ) {

                (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
                Header->ValidDataLength = NewFileSize;
                ExReleaseResourceLite( Header->PagingIoResource );

            } else {

                Header->ValidDataLength = NewFileSize;
            }
        }

        //
        //  Set this handle as having modified the file
        //

        FileObject->Flags |= FO_FILE_MODIFIED;

        if (FileSizeChanged) {

            *CcGetFileSizePointer(FileObject) = NewFileSize;

            FileObject->Flags |= FO_FILE_SIZE_CHANGED;
        }

    //
    //  If we did not succeed, then we must restore the original FileSize
    //  and release the resource.  In the success path, the cache manager
    //  will release the resource.
    //

    } else {

        if (FileSizeChanged) {

            if ( Header->PagingIoResource != NULL ) {

                (VOID)ExAcquireResourceExclusiveLite( Header->PagingIoResource, TRUE );
                Header->FileSize = OldFileSize;
                Header->ValidDataLength = OldValidDataLength;
                ExReleaseResourceLite( Header->PagingIoResource );

            } else {

                Header->FileSize = OldFileSize;
                Header->ValidDataLength = OldValidDataLength;
            }
        }
    }

    //
    //  Now we can release the resource.
    //

    ExReleaseResourceLite( Header->Resource );

    FsRtlExitFileSystem();

    return Status;
}


//
//  The old routine will either dispatch or call FsRtlPrepareMdlWriteDev
//

BOOLEAN
FsRtlPrepareMdlWrite (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in ULONG LockKey,
    __out PMDL *MdlChain,
    __out PIO_STATUS_BLOCK IoStatus
    )

/*++

Routine Description:

    This routine does a fast cached mdl read bypassing the usual file system
    entry routine (i.e., without the Irp).  It is used to do a copy read
    of a cached file object.  For a complete description of the arguments
    see CcMdlRead.

Arguments:

    FileObject - Pointer to the file object being read.

    FileOffset - Byte offset in file for desired data.

    Length - Length of desired data in bytes.

    MdlChain - On output it returns a pointer to an MDL chain describing
        the desired data.

    IoStatus - Pointer to standard I/O status block to receive the status
               for the transfer.

Return Value:

    FALSE - if the data was not written, or if there is an I/O error.

    TRUE - if the data is being written

--*/

{
    PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
    PFAST_IO_DISPATCH FastIoDispatch;

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;

    //
    //  See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
    //

    if ((FastIoDispatch != NULL) &&
        (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, PrepareMdlWrite)) &&
        (FastIoDispatch->PrepareMdlWrite != NULL)) {

        return FastIoDispatch->PrepareMdlWrite( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );

    } else {

        //
        //  Get the DeviceObject for the volume.  If that DeviceObject is different, and
        //  it specifies the FastIo routine, then we have to return FALSE here and cause
        //  an Irp to get generated.
        //

        VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
        if ((VolumeDeviceObject != DeviceObject) &&
            (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
            (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, PrepareMdlWrite)) &&
            (FastIoDispatch->PrepareMdlWrite != NULL)) {

            return FALSE;

        //
        //  Otherwise, call the default routine.
        //

        } else {

            return FsRtlPrepareMdlWriteDev( FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject );
        }
    }
}


//
//  The old routine will either dispatch or call FsRtlMdlWriteCompleteDev
//

BOOLEAN
FsRtlMdlWriteComplete (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in PMDL MdlChain
    )

/*++

Routine Description:

    This routine completes an Mdl write.

Arguments:

    FileObject - Pointer to the file object being read.

    MdlChain - Supplies a pointer to an MDL chain returned from CcMdlPrepareMdlWrite.

Return Value:



--*/

{
    PDEVICE_OBJECT DeviceObject, VolumeDeviceObject;
    PFAST_IO_DISPATCH FastIoDispatch;

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;

    //
    //  See if the (top-level) FileSystem has a FastIo routine, and if so, call it.
    //

    if ((FastIoDispatch != NULL) &&
        (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteComplete)) &&
        (FastIoDispatch->MdlWriteComplete != NULL)) {

        return FastIoDispatch->MdlWriteComplete( FileObject, FileOffset, MdlChain, DeviceObject );

    } else {

        //
        //  Get the DeviceObject for the volume.  If that DeviceObject is different, and
        //  it specifies the FastIo routine, then we have to return FALSE here and cause
        //  an Irp to get generated.
        //

        VolumeDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );
        if ((VolumeDeviceObject != DeviceObject) &&
            (FastIoDispatch = VolumeDeviceObject->DriverObject->FastIoDispatch) &&
            (FastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET(FAST_IO_DISPATCH, MdlWriteComplete)) &&
            (FastIoDispatch->MdlWriteComplete != NULL)) {

            return FALSE;

        //
        //  Otherwise, call the default routine.
        //

        } else {

            return FsRtlMdlWriteCompleteDev( FileObject, FileOffset, MdlChain, DeviceObject );
        }
    }
}


BOOLEAN
FsRtlMdlWriteCompleteDev (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in PMDL MdlChain,
    __in PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine completes an Mdl write.

Arguments:

    FileObject - Pointer to the file object being read.

    MdlChain - Supplies a pointer to an MDL chain returned from CcMdlPrepareMdlWrite.

    DeviceObject - Supplies the DeviceObject for the callee.

Return Value:



--*/


{
    UNREFERENCED_PARAMETER (DeviceObject);

    //
    //  Do not support WRITE_THROUGH in the fast path call.
    //

    if (FlagOn( FileObject->Flags, FO_WRITE_THROUGH )) {
        return FALSE;
    }

    CcMdlWriteComplete2( FileObject, FileOffset, MdlChain );
    return TRUE;
}


NTKERNELAPI
NTSTATUS
FsRtlRegisterFileSystemFilterCallbacks (
    __in PDRIVER_OBJECT FilterDriverObject,
    __in PFS_FILTER_CALLBACKS Callbacks
    )

/*++

Routine Description:

    This routine registers the FilterDriverObject to receive the
    notifications specified in Callbacks at the appropriate times
    for the devices to which this driver is attached.

    This should only be called by a file system filter during
    its DriverEntry routine.

Arguments:

    FileObject - Pointer to the file object being written.

    EndingOffset - The offset of the last byte being written + 1.

    ByteCount - Length of data in bytes.

    ResourceToRelease - Returns the resource to release.  Not defined if
        FALSE is returned.

Return Value:

    STATUS_SUCCESS - The callbacks were successfully registered
        for this driver.

    STATUS_INSUFFICIENT_RESOURCES - There wasn't enough memory to
        store these callbacks for the driver.

    STATUS_INVALID_PARAMETER - Returned in any of the parameters
        are invalid.

--*/

{
    PDRIVER_EXTENSION DriverExt;
    PFS_FILTER_CALLBACKS FsFilterCallbacks;

    PAGED_CODE();

    if (!(ARGUMENT_PRESENT( FilterDriverObject ) &&
          ARGUMENT_PRESENT( Callbacks ))) {

        return STATUS_INVALID_PARAMETER;
    }

    DriverExt = FilterDriverObject->DriverExtension;

    FsFilterCallbacks = ExAllocatePoolWithTag( NonPagedPool,
                                               Callbacks->SizeOfFsFilterCallbacks,
                                               FSRTL_FILTER_MEMORY_TAG );

    if (FsFilterCallbacks == NULL) {

        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlCopyMemory( FsFilterCallbacks,
                   Callbacks,
                   Callbacks->SizeOfFsFilterCallbacks );

    DriverExt->FsFilterCallbacks = FsFilterCallbacks;

    return STATUS_SUCCESS;
}


NTKERNELAPI
BOOLEAN
FsRtlAcquireFileForModWrite (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER EndingOffset,
    OUT PERESOURCE *ResourceToRelease
    )

/*++

Routine Description:

    This routine decides which file system resource the modified page
    writer should acquire and acquires it if possible.  Wait is always
    specified as FALSE.  We pass back the resource Mm has to release
    when the write completes.

    This routine is obsolete --- should call FsRtlAcquireFileForModWriteEx
    instead.

Arguments:

    FileObject - Pointer to the file object being written.

    EndingOffset - The offset of the last byte being written + 1.

    ByteCount - Length of data in bytes.

    ResourceToRelease - Returns the resource to release.  Not defined if
        FALSE is returned.

Return Value:

    FALSE - The resource could not be acquired without waiting.

    TRUE - The returned resource has been acquired.

--*/

{
    NTSTATUS Status;

    //
    //  Just call the new version of this routine and process
    //  the NTSTATUS returned into TRUE for success and FALSE
    //  for failure.
    //

    Status = FsRtlAcquireFileForModWriteEx( FileObject,
                                            EndingOffset,
                                            ResourceToRelease );

    if (!NT_SUCCESS( Status )) {

        return FALSE;

    }

    return TRUE;
}


NTKERNELAPI
NTSTATUS
FsRtlAcquireFileForModWriteEx (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER EndingOffset,
    OUT PERESOURCE *ResourceToRelease
    )
/*++

Routine Description:

    This routine decides which file system resource the modified page
    writer should acquire and acquires it if possible.  Wait is always
    specified as FALSE.  We pass back the resource Mm has to release
    when the write completes.

    The operation is presented to any file system filters attached to this
    volume before and after the file system is asked to acquire this resource.

Arguments:

    FileObject - Pointer to the file object being written.

    EndingOffset - The offset of the last byte being written + 1.

    ByteCount - Length of data in bytes.

    ResourceToRelease - Returns the resource to release.  Not defined if
        FALSE is returned.

Return Value:

    FALSE - The resource could not be acquired without waiting.

    TRUE - The returned resource has been acquired.

--*/
{

    PDEVICE_OBJECT DeviceObject;
    PDEVICE_OBJECT BaseFsDeviceObject;
    FS_FILTER_CTRL FsFilterCtrl;
    PFS_FILTER_CALLBACK_DATA CallbackData;
    PFSRTL_COMMON_FCB_HEADER Header;
    PERESOURCE ResourceAcquired;
    PFAST_IO_DISPATCH FastIoDispatch;
    PFS_FILTER_CALLBACKS FsFilterCallbacks;
    BOOLEAN AcquireExclusive;
    PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
    NTSTATUS Status = STATUS_SUCCESS;
    BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
    BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
    BOOLEAN BaseFsFailedOperation = FALSE;

    //
    //  There are cases when the device that is the base fs device for
    //  this file object will register for the FsFilter callbacks instead of
    //  the legacy FastIo interfaces (DFS does this).  It then can redirect
    //  these operations to another stack that could possibly have file system
    //  filter drivers correctly.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );

    FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
    FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );

    //
    //  The BaseFsDeviceObject should only support one of these interfaces --
    //  either the FastIoDispatch interface for the FsFilterCallbacks interface.
    //  If a device provides support for both interfaces, we will only use
    //  the FsFilterCallback interface.
    //

    ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForModWrite ) &&
              (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForModifiedPageWriter ) ||
               VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForModifiedPageWriter ))) );

    if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForModifiedPageWriter ) ||
        VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForModifiedPageWriter )) {

        BaseFsGetsFsFilterCallbacks = TRUE;
    }

    if (DeviceObject == BaseFsDeviceObject &&
        !BaseFsGetsFsFilterCallbacks) {

        //
        //  There are no filters attached to this device and the base file system
        //  does not want these callbacks. This quick check allows us to bypass the
        //  logic to see if any filters are interested.
        //

        CallFilters = NULL;
    }

    if (CallFilters) {

        //
        //  Call routine to initialize the control structure.
        //

        Status = FsFilterCtrlInit( &FsFilterCtrl,
                                   FS_FILTER_ACQUIRE_FOR_MOD_WRITE,
                                   DeviceObject,
                                   BaseFsDeviceObject,
                                   FileObject,
                                   TRUE );

        if (!NT_SUCCESS( Status )) {

            return Status;
        }

        //
        // Initialize the operation-specific parameters in the callback data.
        //

        CallbackData = &(FsFilterCtrl.Data);
        CallbackData->Parameters.AcquireForModifiedPageWriter.EndingOffset = EndingOffset;
        CallbackData->Parameters.AcquireForModifiedPageWriter.ResourceToRelease = ResourceToRelease;

        Status = FsFilterPerformCallbacks( &FsFilterCtrl,
                                           TRUE,
                                           TRUE,
                                           &BaseFsFailedOperation );
    }

    if (Status == STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY) {

        //
        //  The filter/file system completed the operation, therefore we just need to
        //  call the completion callbacks for this operation.  There is no need to try
        //  to call the base file system.
        //

        Status = STATUS_SUCCESS;

    } else if (NT_SUCCESS( Status )) {

        if (CallFilters) {

            //
            // Always copy out file object
            //

            FileObject = FsFilterCtrl.Data.FileObject;

            if (FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {

                BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
                ReleaseBaseFsDeviceReference = TRUE;
                FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
                FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
            }
        }

        if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForModifiedPageWriter ) ||
              VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForModifiedPageWriter ))) {

            //
            //  Call the base file system.
            //

            if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForModWrite )) {

                Status = FastIoDispatch->AcquireForModWrite( FileObject,
                                                             EndingOffset,
                                                             ResourceToRelease,
                                                             BaseFsDeviceObject );
            } else {

                Status = STATUS_INVALID_DEVICE_REQUEST;
            }

            //
            //  If there is a failure at this point, we know that the failure
            //  was caused by the base file system.
            //

            BaseFsFailedOperation = TRUE;
        }

        if (ReleaseBaseFsDeviceReference) {

            ObDereferenceObject( BaseFsDeviceObject );
        }
    }

    ASSERT( (Status == STATUS_SUCCESS) ||
            (Status == STATUS_CANT_WAIT) ||
            (Status == STATUS_INVALID_DEVICE_REQUEST) );

    //
    //  If the base file system didn't have an AcquireForModWrite handler
    //  or couldn't return STATUS_SUCCESS or STATUS_CANT_WAIT,
    //  we need to perform the default actions here.
    //

    if ((Status != STATUS_SUCCESS) &&
        (Status != STATUS_CANT_WAIT) &&
        BaseFsFailedOperation) {

        //
        //  We follow the following rules to determine which resource
        //  to acquire.  We use the flags in the common header.  These
        //  flags can't change once we have acquired any resource.
        //  This means we can do an unsafe test and optimistically
        //  acquire a resource.  At that point we can test the bits
        //  to see if we have what we want.
        //
        //  0 - If there is no main resource, acquire nothing.
        //
        //  1 - Acquire the main resource exclusively if the
        //      ACQUIRE_MAIN_RSRC_EX flag is set or we are extending
        //      valid data.
        //
        //  2 - Acquire the main resource shared if there is
        //      no paging io resource or the
        //      ACQUIRE_MAIN_RSRC_SH flag is set.
        //
        //  3 - Otherwise acquire the paging io resource shared.
        //

        Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;

        if (Header->Resource == NULL) {

            *ResourceToRelease = NULL;

            Status = STATUS_SUCCESS;
            goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
        }

        if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX ) ||
            (EndingOffset->QuadPart > Header->ValidDataLength.QuadPart &&
             Header->ValidDataLength.QuadPart != Header->FileSize.QuadPart)) {

            ResourceAcquired = Header->Resource;
            AcquireExclusive = TRUE;

        } else if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH ) ||
                   Header->PagingIoResource == NULL) {

            ResourceAcquired = Header->Resource;
            AcquireExclusive = FALSE;

        } else {

            ResourceAcquired = Header->PagingIoResource;
            AcquireExclusive = FALSE;
        }

        //
        //  Perform the following in a loop in case we need to back and
        //  check the state of the resource acquisition.  In most cases
        //  the initial checks will succeed and we can proceed immediately.
        //  We have to worry about the two FsRtl bits changing but
        //  if there is no paging io resource before there won't ever be
        //  one.
        //

        while (TRUE) {

            //
            //  Now acquire the desired resource.
            //

            if (AcquireExclusive) {

                if (!ExAcquireResourceExclusiveLite( ResourceAcquired, FALSE )) {

                    Status = STATUS_CANT_WAIT;
                    goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
                }

            } else if (!ExAcquireSharedWaitForExclusive( ResourceAcquired, FALSE )) {

                Status = STATUS_CANT_WAIT;
                goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
            }

            //
            //  If the valid data length is changing or the exclusive bit is
            //  set and we don't have the main resource exclusive then
            //  release the current resource and acquire the main resource
            //  exclusively and move to the top of the loop.
            //
            //  We must get it exclusive in all cases where the ending offset
            //  is beyond vdl.  It used to be allowed shared if vdl == fs, but
            //  this neglected the possibility that the file could be extended
            //  under our shared (pagingio) access.
            //

            if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_EX ) ||
                EndingOffset->QuadPart > Header->ValidDataLength.QuadPart) {

                //
                //  If we don't have the main resource exclusively then
                //  release the current resource and attempt to acquire
                //  the main resource exclusively.
                //

                if (!AcquireExclusive) {

                    ExReleaseResourceLite( ResourceAcquired );
                    AcquireExclusive = TRUE;
                    ResourceAcquired = Header->Resource;
                    continue;
                }

                //
                //  We have the correct resource.  Exit the loop.
                //

            //
            //  If we should be acquiring the main resource shared then move
            //  to acquire the correct resource and proceed to the top of the loop.
            //

            } else if (FlagOn( Header->Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH )) {

                //
                //  If we have the main resource exclusively then downgrade to
                //  shared and exit the loop.
                //

                if (AcquireExclusive) {

                    ExConvertExclusiveToSharedLite( ResourceAcquired );

                //
                //  If we have the paging io resource then give up this resource
                //  and acquire the main resource exclusively.  This is going
                //  at it with a large hammer but is guaranteed to be resolved
                //  in the next pass through the loop.
                //

                } else if (ResourceAcquired != Header->Resource) {

                    ExReleaseResourceLite( ResourceAcquired );
                    ResourceAcquired = Header->Resource;
                    AcquireExclusive = TRUE;
                    continue;
                }

                //
                //  We have the correct resource.  Exit the loop.
                //

            //
            //  At this point we should have the paging Io resource shared
            //  if it exists.  If not then acquire it shared and release the
            //  other resource and exit the loop.
            //

            } else if (Header->PagingIoResource != NULL
                       && ResourceAcquired != Header->PagingIoResource) {

                ResourceAcquired = NULL;

                if (ExAcquireSharedWaitForExclusive( Header->PagingIoResource, FALSE )) {

                    ResourceAcquired = Header->PagingIoResource;
                }

                ExReleaseResourceLite( Header->Resource );

                if (ResourceAcquired == NULL) {

                    Status = STATUS_CANT_WAIT;
                    goto FsRtlAcquireFileForModWrite_CallCompletionCallbacks;
                }

                //
                //  We now have the correct resource.  Exit the loop.
                //

            //
            //  We should have the main resource shared.  If we don't then
            //  degrade our lock to shared access.
            //

            } else if (AcquireExclusive) {

                ExConvertExclusiveToSharedLite( ResourceAcquired );

                //
                //  We now have the correct resource.  Exit the loop.
                //
            }

            //
            //  We have the correct resource.  Exit the loop.
            //

            break;
        }

        *ResourceToRelease = ResourceAcquired;

        Status = STATUS_SUCCESS;
    }

FsRtlAcquireFileForModWrite_CallCompletionCallbacks:

    //
    //  Again, we only want to call try to do completion callbacks
    //  if there are any filters attached to this device that have
    //  completion callbacks.  In any case, if we called down to the filters
    //  we need to free the FsFilterCtrl.
    //

    if (CallFilters) {

        if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {

            FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
        }

        FsFilterCtrlFree( &FsFilterCtrl );
    }

#if DBG

    if (NT_SUCCESS( Status )) {

        gCounter.AcquireFileForModWriteEx_Succeed ++;

    } else {

        gCounter.AcquireFileForModWriteEx_Fail ++;
    }

#endif

    return Status;
}


NTKERNELAPI
VOID
FsRtlReleaseFileForModWrite (
    IN PFILE_OBJECT FileObject,
    IN PERESOURCE ResourceToRelease
    )

/*++

Routine Description:

    This routine releases a file system resource previously acquired for
    the modified page writer.

Arguments:

    FileObject - Pointer to the file object being written.

    ResourceToRelease - Supplies the resource to release.  Not defined if
        FALSE is returned.

Return Value:

    None.

--*/

{
    PDEVICE_OBJECT BaseFsDeviceObject, DeviceObject;
    PFAST_IO_DISPATCH FastIoDispatch;
    PFS_FILTER_CALLBACKS FsFilterCallbacks;
    FS_FILTER_CTRL FsFilterCtrl;
    PFS_FILTER_CALLBACK_DATA CallbackData;
    PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
    NTSTATUS Status = STATUS_SUCCESS;
    BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
    BOOLEAN ReleaseBaseDeviceReference = FALSE;
    BOOLEAN BaseFsFailedOperation = FALSE;

#if DBG
    gCounter.ReleaseFileForModWrite ++;
#endif

    //
    //  There are cases when the device that is the base fs device for
    //  this file object will register for the FsFilter callbacks instead of
    //  the legacy FastIo interfaces (DFS does this).  It then can redirect
    //  these operations to another stack that could possibly have file system
    //  filter drivers correctly.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );

    FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
    FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );

    //
    //  The BaseFsDeviceObject should only support one of these interfaces --
    //  either the FastIoDispatch interface for the FsFilterCallbacks interface.
    //  If a device provides support for both interfaces, we will only use
    //  the FsFilterCallback interface.
    //

    ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForModWrite ) &&
              (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForModifiedPageWriter ) ||
               VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForModifiedPageWriter ))) );

    if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForModifiedPageWriter ) ||
        VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForModifiedPageWriter )) {

        BaseFsGetsFsFilterCallbacks = TRUE;
    }

    if (DeviceObject == BaseFsDeviceObject &&
        !BaseFsGetsFsFilterCallbacks) {

        //
        //  There are no filters attached to this device and the base file system
        //  does not want these callbacks. This quick check allows us to bypass the
        //  logic to see if any filters are interested.
        //

        CallFilters = NULL;
    }

    if (CallFilters) {

        FsFilterCtrlInit( &FsFilterCtrl,
                          FS_FILTER_RELEASE_FOR_MOD_WRITE,
                          DeviceObject,
                          BaseFsDeviceObject,
                          FileObject,
                          FALSE );

        //
        // Initialize the operation-specific parameters in the callback data.
        //

        CallbackData = &(FsFilterCtrl.Data);
        CallbackData->Parameters.ReleaseForModifiedPageWriter.ResourceToRelease = ResourceToRelease;

        Status = FsFilterPerformCallbacks( &FsFilterCtrl,
                                           FALSE,
                                           TRUE,
                                           &BaseFsFailedOperation );
    }

    if (Status == STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY) {

        //
        //  The filter/file system completed the operation, therefore we just need to
        //  call the completion callbacks for this operation.  There is no need to try
        //  to call the base file system.
        //

        Status = STATUS_SUCCESS;

    } else if (NT_SUCCESS( Status )) {

        if (CallFilters) {

            //
            // Always copy out file object
            //

            FileObject = FsFilterCtrl.Data.FileObject;

            if (FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {

                BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
                ReleaseBaseDeviceReference = TRUE;
                FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
                FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
            }
        }

        if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForModifiedPageWriter ) ||
              VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForModifiedPageWriter ))) {

            //
            //  Call the base file system.
            //

            if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForModWrite )) {

                Status = FastIoDispatch->ReleaseForModWrite( FileObject,
                                                             ResourceToRelease,
                                                             BaseFsDeviceObject );

            } else {

                Status = STATUS_INVALID_DEVICE_REQUEST;
            }

            //
            //  If there is a failure at this point, we know that the failure
            //  was caused by the base file system.
            //

            BaseFsFailedOperation = TRUE;
        }

        if (ReleaseBaseDeviceReference) {

            ObDereferenceObject( BaseFsDeviceObject );
        }
    }

    //
    //  We expect STATUS_SUCCESS to be returned if the operation was completely 
    //  processed by the ReleaseForModWrite handler or 
    //  STATUS_INVALID_DEVICE_REQUEST if the default processing is being 
    //  requested.  To protect against incorrect driver implementation, we will 
    //  do the default logic on any non-success status code if we think the
    //  base file system has failed the release operation.
    //

    ASSERT( (Status == STATUS_SUCCESS) ||
            (Status == STATUS_INVALID_DEVICE_REQUEST) );

    //
    //  If the base file system doesn't provide a handler for this
    //  operation or the handler couldn't release the lock, perform the
    //  default action, which is releasing the ResourceToRelease.
    //

    if (!NT_SUCCESS( Status ) &&
        BaseFsFailedOperation) {

        ExReleaseResourceLite( ResourceToRelease );
        Status = STATUS_SUCCESS;
    }

    //
    //  Again, we only want to try to do completion callbacks
    //  if there are any filters attached to this device that have
    //  completion callbacks.  In any case, if we called down to the filters
    //  we need to free the FsFilterCtrl.
    //

    if (CallFilters) {

        if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {

            FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
        }

        FsFilterCtrlFree( &FsFilterCtrl );
    }
}


NTKERNELAPI
VOID
FsRtlAcquireFileForCcFlush (
    IN PFILE_OBJECT FileObject
    )

/*++

Routine Description:

    This routine acquires a file system resource prior to a call to CcFlush.

    This routine is obsolete --- FsRtlAcquireFileForCcFlushEx should
    be used instead.

Arguments:

    FileObject - Pointer to the file object being written.

Return Value:

    None.

--*/

{
    NTSTATUS Status;

    PAGED_CODE();

    //
    //  Just call the new version of this routine and ignore
    //  the return value.  In the debug version, we will assert
    //  if we see a failure here to encourage people to call the
    //  FsRtlAcquireFileForCcFlushEx.
    //

    Status = FsRtlAcquireFileForCcFlushEx( FileObject );

    ASSERT( NT_SUCCESS( Status ) );
}


NTKERNELAPI
NTSTATUS
FsRtlAcquireFileForCcFlushEx (
    IN PFILE_OBJECT FileObject
    )

/*++

Routine Description:

    This routine acquires a file system resource prior to a call to CcFlush.
    This operation is presented to all the file system filters in the
    filter stack for this volume.  If all filters success the operation,
    the base file system is requested to acquire the file system resource
    for CcFlush.

Arguments:

    FileObject - Pointer to the file object being written.

Return Value:

    None.

--*/

{

    PDEVICE_OBJECT DeviceObject;
    PDEVICE_OBJECT BaseFsDeviceObject;
    FS_FILTER_CTRL FsFilterCtrl;
    PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
    NTSTATUS Status = STATUS_SUCCESS;
    PFAST_IO_DISPATCH FastIoDispatch;
    PFS_FILTER_CALLBACKS FsFilterCallbacks;
    BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
    BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
    BOOLEAN BaseFsFailedOperation = FALSE;

    PAGED_CODE();

    //
    //  There are cases when the device that is the base fs device for
    //  this file object will register for the FsFilter callbacks instead of
    //  the legacy FastIo interfaces (DFS does this).  It then can redirect
    //  these operations to another stack that could possibly have file system
    //  filter drivers correctly.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );

    FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
    FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );

    //
    //  The BaseFsDeviceObject should only support one of these interfaces --
    //  either the FastIoDispatch interface for the FsFilterCallbacks interface.
    //  If a device provides support for both interfaces, we will only use
    //  the FsFilterCallback interface.
    //

    ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForCcFlush ) &&
              (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForCcFlush ) ||
               VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForCcFlush ))) );

    if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForCcFlush ) ||
        VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForCcFlush )) {

        BaseFsGetsFsFilterCallbacks = TRUE;
    }

    if (DeviceObject == BaseFsDeviceObject &&
        !BaseFsGetsFsFilterCallbacks) {

        //
        //  There are no filters attached to this device and the base file system
        //  does not want these callbacks. This quick check allows us to bypass the
        //  logic to see if any filters are interested.
        //

        CallFilters = NULL;
    }

    if (CallFilters) {

        //
        //  Call routine to initialize the control structure.
        //

        Status = FsFilterCtrlInit( &FsFilterCtrl,
                                   FS_FILTER_ACQUIRE_FOR_CC_FLUSH,
                                   DeviceObject,
                                   BaseFsDeviceObject,
                                   FileObject,
                                   TRUE );

        if (!NT_SUCCESS( Status )) {

            return Status;
        }

        //
        //  There are no operation specific parameters for this
        //  operation, so just perform the pre-callbacks.
        //

        FsRtlEnterFileSystem();

        Status = FsFilterPerformCallbacks( &FsFilterCtrl,
                                           TRUE,
                                           TRUE,
                                           &BaseFsFailedOperation );

    } else {

        //
        //  We don't have any filters to call, but we still need
        //  to disable APCs.
        //

        FsRtlEnterFileSystem();
    }

    if (Status == STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY) {

        //
        //  The filter/file system completed the operation, therefore we just need to
        //  call the completion callbacks for this operation.  There is no need to try
        //  to call the base file system.
        //

        Status = STATUS_SUCCESS;

    } else if (NT_SUCCESS( Status )) {

        if (CallFilters) {

            //
            // Always copy out file object
            //

            FileObject = FsFilterCtrl.Data.FileObject;

            if (FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {

                BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
                ReleaseBaseFsDeviceReference = TRUE;
                FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
                FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
            }
        }

        if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForCcFlush ) ||
              VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForCcFlush))) {

            //
            //  Call the base file system.
            //

            if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireForCcFlush )) {

                Status = FastIoDispatch->AcquireForCcFlush( FileObject,
                                                            BaseFsDeviceObject );

            } else {

                Status = STATUS_INVALID_DEVICE_REQUEST;
            }

            //
            //  If there is a failure at this point, we know that the failure
            //  was caused by the base file system.
            //

            BaseFsFailedOperation = TRUE;
        }

        if (ReleaseBaseFsDeviceReference) {

            ObDereferenceObject( BaseFsDeviceObject );
        }
    }

    ASSERT( (Status == STATUS_SUCCESS) ||
            (Status == STATUS_INVALID_DEVICE_REQUEST) );

    //
    //  If the file system doesn't have a dispatch handler or failed this
    //  this operation, try to acquire the appropriate resources ourself.
    //

    if (Status == STATUS_INVALID_DEVICE_REQUEST &&
        BaseFsFailedOperation) {

        PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext;

        //
        //  If not already owned get the main resource exclusive because we may
        //  extend ValidDataLength.  Otherwise acquire it one more time recursively.
        //

        if (Header->Resource != NULL) {

            if (!ExIsResourceAcquiredSharedLite( Header->Resource )) {

                ExAcquireResourceExclusiveLite( Header->Resource, TRUE );

            } else {

                ExAcquireResourceSharedLite( Header->Resource, TRUE );
            }
        }

        //
        //  Also get the paging I/O resource ahead of any MM resources.
        //

        if (Header->PagingIoResource != NULL) {

            ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
        }

        Status = STATUS_SUCCESS;
    }

    //
    //  Again, we only want to call try to do completion callbacks
    //  if there are any filters attached to this device that have
    //  completion callbacks.  In any case, if we called down to the filters
    //  we need to free the FsFilterCtrl.
    //

    if (CallFilters) {

        if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {

            FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
        }

        FsFilterCtrlFree( &FsFilterCtrl );
    }

    //
    //  If this lock was not successfully acquired, then the lock
    //  will not need to be released.  Therefore, we need to call
    //  FsRtlExitFileSystem now.
    //

    if (!NT_SUCCESS( Status )) {

        FsRtlExitFileSystem();
    }

#if DBG

    if (NT_SUCCESS( Status )) {

        gCounter.AcquireFileForCcFlushEx_Succeed ++;

    } else {

        gCounter.AcquireFileForCcFlushEx_Fail ++;
    }

#endif

    return Status;
}


NTKERNELAPI
VOID
FsRtlReleaseFileForCcFlush (
    IN PFILE_OBJECT FileObject
    )

/*++

Routine Description:

    This routine releases a file system resource previously acquired for
    the CcFlush.

Arguments:

    FileObject - Pointer to the file object being written.

Return Value:

    None.

--*/

{
    PDEVICE_OBJECT BaseFsDeviceObject, DeviceObject;
    FS_FILTER_CTRL FsFilterCtrl;
    PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
    NTSTATUS Status = STATUS_SUCCESS;
    PFAST_IO_DISPATCH FastIoDispatch;
    PFS_FILTER_CALLBACKS FsFilterCallbacks;
    BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
    BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
    BOOLEAN BaseFsFailedOperation = FALSE;

    PAGED_CODE();

#if DBG
    gCounter.ReleaseFileForCcFlush ++;
#endif

    //
    //  There are cases when the device that is the base fs device for
    //  this file object will register for the FsFilter callbacks instead of
    //  the legacy FastIo interfaces (DFS does this).  It then can redirect
    //  these operations to another stack that could possibly have file system
    //  filter drivers correctly.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );

    FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
    FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );

    //
    //  The BaseFsDeviceObject should only support one of these interfaces --
    //  either the FastIoDispatch interface for the FsFilterCallbacks interface.
    //  If a device provides support for both interfaces, we will only use
    //  the FsFilterCallback interface.
    //

    ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForCcFlush ) &&
              (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForCcFlush ) ||
               VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForCcFlush ))) );

    if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForCcFlush ) ||
        VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForCcFlush )) {

        BaseFsGetsFsFilterCallbacks = TRUE;
    }

    if (DeviceObject == BaseFsDeviceObject &&
        !BaseFsGetsFsFilterCallbacks) {

        //
        //  There are no filters attached to this device and the base file system
        //  does not want these callbacks. This quick check allows us to bypass the
        //  logic to see if any filters are interested.
        //


        CallFilters = NULL;
    }

    if (CallFilters) {

        FsFilterCtrlInit( &FsFilterCtrl,
                          FS_FILTER_RELEASE_FOR_CC_FLUSH,
                          DeviceObject,
                          BaseFsDeviceObject,
                          FileObject,
                          FALSE );

        //
        //  There are no operation-specific parameters to initialize,
        //  so perform the pre-operation callbacks.
        //

        Status = FsFilterPerformCallbacks( &FsFilterCtrl,
                                           FALSE,
                                           TRUE,
                                           &BaseFsFailedOperation );
    }

    if (Status == STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY) {

        //
        //  The filter/file system completed the operation, therefore we just need to
        //  call the completion callbacks for this operation.  There is no need to try
        //  to call the base file system.
        //

        Status = STATUS_SUCCESS;

    } else if (NT_SUCCESS( Status )) {

        if (CallFilters) {

            //
            // Always copy out file object
            //

            FileObject = FsFilterCtrl.Data.FileObject;

            if (FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {

                BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
                ReleaseBaseFsDeviceReference = TRUE;
                FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
                FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
            }
        }

        if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForCcFlush ) ||
              VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForCcFlush ))) {

            //
            //  Call the base file system.
            //

            if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseForCcFlush )) {

                Status = FastIoDispatch->ReleaseForCcFlush( FileObject, BaseFsDeviceObject );

            } else {

                Status = STATUS_INVALID_DEVICE_REQUEST;
            }

            //
            //  If there is a failure at this point, we know that the failure
            //  was caused by the base file system.
            //

            BaseFsFailedOperation = TRUE;
        }

        if (ReleaseBaseFsDeviceReference) {

            ObDereferenceObject( BaseFsDeviceObject );
        }
    }

    ASSERT( (Status == STATUS_SUCCESS) ||
            (Status == STATUS_INVALID_DEVICE_REQUEST) );

    if (Status == STATUS_INVALID_DEVICE_REQUEST &&
        BaseFsFailedOperation) {

        PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext;

        //
        //  The base file system doesn't provide a handler for this
        //  operation, so perform the default actions.
        //

        //
        //  Free whatever we could have acquired.
        //

        if (Header->PagingIoResource != NULL) {

            ExReleaseResourceLite( Header->PagingIoResource );
        }

        if (Header->Resource != NULL) {

            ExReleaseResourceLite( Header->Resource );
        }

        Status = STATUS_SUCCESS;
    }

    ASSERT( Status == STATUS_SUCCESS );

    //
    //  Again, we only want to call try to do completion callbacks
    //  if there are any filters attached to this device that have
    //  completion callbacks.  In any case, if we called down to the filters
    //  we need to free the FsFilterCtrl.
    //

    if (CallFilters) {

        if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {

            FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
        }

        FsFilterCtrlFree( &FsFilterCtrl );
    }

    FsRtlExitFileSystem();
}


NTKERNELAPI
VOID
FsRtlAcquireFileExclusive (
    __in PFILE_OBJECT FileObject
    )

/*++

Routine Description:

    This routine is used by NtCreateSection to pre-acquire file system
    resources in order to avoid deadlocks.  If there is a FastIo entry
    for AcquireFileForNtCreateSection then that routine will be called.
    Otherwise, we will simply acquire the main file resource exclusive.
    If there is no main resource then we acquire nothing and return
    FALSE.  In the cases that we acquire a resource, we also set the
    TopLevelIrp field in the thread local storage to indicate to file
    systems beneath us that we have acquired file system resources.

Arguments:

    FileObject - Pointer to the file object being written.

Return Value:

    NONE

--*/

{
    NTSTATUS Status;

    PAGED_CODE();

    //
    //  Just call the common version of this function,
    //  FsRtlAcquireFileExclusiveCommon.
    //

    Status = FsRtlAcquireFileExclusiveCommon( FileObject, SyncTypeOther, 0 );

    //
    //  This should always be STATUS_SUCCESS since we are not
    //  allowing failures and the file system cannot fail
    //  this operation...
    //

    ASSERT( NT_SUCCESS( Status ) );
}


NTKERNELAPI
NTSTATUS
FsRtlAcquireToCreateMappedSection (
    IN PFILE_OBJECT FileObject,
    IN ULONG SectionPageProtection
    )

/*++

Routine Description:

    This routine is meant to replace FsRtlAcquireFileExclusive for
    the memory manager.  Mm calls this routine to synchronize
    for a mapped section create, but filters are allowed
    to fail this operation.  Other components that want to
    synchronize with section creation should call
    FsRtlAcquireFileExclusive.

    This routine calls FsRtlAcquireFileExclusiveCommon to do
    all the work.

    This routine is used by NtCreateSection to pre-acquire file system
    resources in order to avoid deadlocks.  If there is a FastIo entry
    for AcquireFileForNtCreateSection then that routine will be called.
    Otherwise, we will simply acquire the main file resource exclusive.
    If there is no main resource then we acquire nothing and return
    FALSE.  In the cases that we acquire a resource, we also set the
    TopLevelIrp field in the thread local storage to indicate to file
    systems beneath us that we have acquired file system resources.

Arguments:

    FileObject - Pointer to the file object being written.
    SectionPageProtection - The access requested for the section being
        created.

Return Value:

    The status of the operation.

--*/

{

    PAGED_CODE();

    return FsRtlAcquireFileExclusiveCommon( FileObject, SyncTypeCreateSection, SectionPageProtection );

}


NTKERNELAPI
NTSTATUS
FsRtlAcquireFileExclusiveCommon (
    IN PFILE_OBJECT FileObject,
    IN FS_FILTER_SECTION_SYNC_TYPE SyncType,
    IN ULONG SectionPageProtection
    )

/*++

Routine Description:

    This routine is used to pre-acquire file system resources in order
    to avoid deadlocks.  The file system filters for this volume
    will be notified about this operation, then, if there is a FastIo
    entry for AcquireFileForNtCreateSection, that routine will be called.
    Otherwise, we will simply acquire the main file resource exclusive.
    If there is no main resource then we acquire nothing and return
    STATUS_SUCCESS.  Finally, the file system filters will be notified
    whether or not this resource has been acquired.

Arguments:

    FileObject - Pointer to the file object being written.
    CreatingMappedSection - TRUE if this lock is being acquired so that
        a mapped section can be created.  Filters are allowed
        to fail this operation.  FALSE otherwise.

Return Value:

    NONE

--*/

{

    PDEVICE_OBJECT DeviceObject, BaseFsDeviceObject;
    FS_FILTER_CTRL FsFilterCtrl;
    PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
    NTSTATUS Status = STATUS_SUCCESS;
    BOOLEAN AllowFilterToFailOperation;
    PFAST_IO_DISPATCH FastIoDispatch;
    PFS_FILTER_CALLBACKS FsFilterCallbacks;
    BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
    BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
    BOOLEAN BaseFsFailedOperation = FALSE;

    PAGED_CODE();

    //
    //  There are cases when the device that is the base fs device for
    //  this file object will register for the FsFilter callbacks instead of
    //  the legacy FastIo interfaces (DFS does this).  It then can redirect
    //  these operations to another stack that could possibly have file system
    //  filter drivers correctly.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );

    FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
    FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );

    //
    //  The BaseFsDeviceObject should only support one of these interfaces --
    //  either the FastIoDispatch interface for the FsFilterCallbacks interface.
    //  If a device provides support for both interfaces, we will only use
    //  the FsFilterCallback interface.
    //

    ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireFileForNtCreateSection ) &&
              (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForSectionSynchronization ) ||
               VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForSectionSynchronization ))) );

    if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForSectionSynchronization ) ||
        VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForSectionSynchronization )) {

        BaseFsGetsFsFilterCallbacks = TRUE;
    }

    if (DeviceObject == BaseFsDeviceObject &&
        !BaseFsGetsFsFilterCallbacks) {

        //
        //  There are no filters attached to this device and the base file system
        //  does not want these callbacks. This quick check allows us to bypass the
        //  logic to see if any filters are interested.
        //

        CallFilters = NULL;
    }

    if (CallFilters) {

        //
        //  Initialize operation specific parameters for this
        //  operation.
        //

        FsFilterCtrl.Data.Parameters.AcquireForSectionSynchronization.SyncType =
            SyncType;
        FsFilterCtrl.Data.Parameters.AcquireForSectionSynchronization.PageProtection =
            SectionPageProtection;

        switch (SyncType) {
        case SyncTypeCreateSection:
            AllowFilterToFailOperation = TRUE;
            break;

        case SyncTypeOther:
        default:
            AllowFilterToFailOperation = FALSE;
        }

        //
        //  Call routine to initialize the control structure.
        //

        Status = FsFilterCtrlInit( &FsFilterCtrl,
                                   FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION,
                                   DeviceObject,
                                   BaseFsDeviceObject,
                                   FileObject,
                                   AllowFilterToFailOperation );

        if (!NT_SUCCESS( Status )) {

            return Status;
        }

        //
        //  There are no operation specific parameters for this
        //  operation, so just perform the pre-callbacks.
        //

        FsRtlEnterFileSystem();

        //
        //  Note: If the filter is allowed to fail the operation, so is the
        //  base file system, so we will just use that variable for both
        //  parameters to FsFilterPerformCallbacks.
        //

        Status = FsFilterPerformCallbacks( &FsFilterCtrl,
                                           AllowFilterToFailOperation,
                                           AllowFilterToFailOperation,
                                           &BaseFsFailedOperation );

    } else {

        //
        //  We don't have any filters to call, but we still need
        //  to disable APCs.
        //

        FsRtlEnterFileSystem();
    }

    if (Status == STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY) {

        //
        //  The filter/file system completed the operation, therefore we just need to
        //  call the completion callbacks for this operation.  There is no need to try
        //  to call the base file system.
        //

        Status = STATUS_SUCCESS;

    } else if (NT_SUCCESS( Status )) {

        if (CallFilters) {

            //
            // Always copy out file object
            //

            FileObject = FsFilterCtrl.Data.FileObject;

            if (FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {

                BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
                ReleaseBaseFsDeviceReference = TRUE;
                FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
                FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
            }
        }

        if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreAcquireForSectionSynchronization ) ||
              VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostAcquireForSectionSynchronization ))) {

            //
            //  Call the base file system.
            //

            if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, AcquireFileForNtCreateSection )) {

                FastIoDispatch->AcquireFileForNtCreateSection( FileObject );

                //
                //  The status should already be STATUS_SUCCESS if we come down
                //  this path.  Since the FastIo handler doesn't return a value
                //  the status should remain STATUS_SUCCESS.
                //

                //  Status = STATUS_SUCCESS;

            } else {

                Status = STATUS_INVALID_DEVICE_REQUEST;
            }

            //
            //  If there is a failure at this point, we know that the failure
            //  was caused by the base file system.
            //

            BaseFsFailedOperation = TRUE;
        }

        if (ReleaseBaseFsDeviceReference) {

            ObDereferenceObject( BaseFsDeviceObject );
        }
    }

    ASSERT( (Status == STATUS_SUCCESS) ||
            (Status == STATUS_INVALID_DEVICE_REQUEST) );

    if (Status == STATUS_INVALID_DEVICE_REQUEST &&
        BaseFsFailedOperation) {

        PFSRTL_COMMON_FCB_HEADER Header;

        //
        //  The file system doesn't have a dispatch handler for this
        //  operation, so try to acquire the appropriate resources
        //  ourself.
        //

        //
        //  If there is a main file resource, acquire that.
        //

        Header = FileObject->FsContext;

        if ((Header != NULL) &&
            (Header->Resource != NULL)) {

            ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
        }

        Status = STATUS_SUCCESS;
    }

    //
    //  Again, we only want to call try to do completion callbacks
    //  if there are any filters attached to this device that have
    //  completion callbacks.  In any case, if we called down to the filters
    //  we need to free the FsFilterCtrl.
    //

    if (CallFilters) {

        if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {

            FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
        }

        FsFilterCtrlFree( &FsFilterCtrl );
    }

    //
    //  If this lock was not successfully acquired, then the lock
    //  will not need to be released.  Therefore, we need to call
    //  FsRtlExitFileSystem now.
    //

    if (!NT_SUCCESS( Status )) {

        FsRtlExitFileSystem();
    }

#if DBG

    if (NT_SUCCESS( Status )) {

        gCounter.AcquireFileExclusiveEx_Succeed ++;

    } else {

        gCounter.AcquireFileExclusiveEx_Fail ++;
    }

#endif

    return Status;
}


NTKERNELAPI
VOID
FsRtlReleaseFile (
    __in PFILE_OBJECT FileObject
    )

/*++

Routine Description:

    This routine releases resources acquired by FsRtlAcquireFileExclusive.

Arguments:

    FileObject - Pointer to the file object being written.

Return Value:

    None.

--*/

{
    PDEVICE_OBJECT BaseFsDeviceObject, DeviceObject;
    FS_FILTER_CTRL FsFilterCtrl;
    PFS_FILTER_CTRL CallFilters = &FsFilterCtrl;
    NTSTATUS Status = STATUS_SUCCESS;
    PFAST_IO_DISPATCH FastIoDispatch;
    PFS_FILTER_CALLBACKS FsFilterCallbacks;
    BOOLEAN BaseFsGetsFsFilterCallbacks = FALSE;
    BOOLEAN ReleaseBaseFsDeviceReference = FALSE;
    BOOLEAN BaseFsFailedOperation = FALSE;

    PAGED_CODE();

#if DBG
    gCounter.ReleaseFile ++;
#endif

    //
    //  There are cases when the device that is the base fs device for
    //  this file object will register for the FsFilter callbacks instead of
    //  the legacy FastIo interfaces (DFS does this).  It then can redirect
    //  these operations to another stack that could possibly have file system
    //  filter drivers correctly.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );
    BaseFsDeviceObject = IoGetBaseFileSystemDeviceObject( FileObject );

    FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
    FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );

    //
    //  The BaseFsDeviceObject should only support one of these interfaces --
    //  either the FastIoDispatch interface for the FsFilterCallbacks interface.
    //  If a device provides support for both interfaces, we will only use
    //  the FsFilterCallback interface.
    //

    ASSERT( !(VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch, ReleaseFileForNtCreateSection ) &&
              (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForSectionSynchronization ) ||
               VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForSectionSynchronization ))) );

    if (VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForSectionSynchronization ) ||
        VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForSectionSynchronization )) {

        BaseFsGetsFsFilterCallbacks = TRUE;
    }

    if (DeviceObject == BaseFsDeviceObject &&
        !BaseFsGetsFsFilterCallbacks) {

        //
        //  There are no filters attached to this device and the base file system
        //  does not want these callbacks. This quick check allows us to bypass the
        //  logic to see if any filters are interested.
        //


        CallFilters = NULL;
    }

    if (CallFilters) {

        FsFilterCtrlInit( &FsFilterCtrl,
                          FS_FILTER_RELEASE_FOR_SECTION_SYNCHRONIZATION,
                          DeviceObject,
                          BaseFsDeviceObject,
                          FileObject,
                          FALSE );

        //
        //  There are no operation-specific parameters to initialize,
        //  so perform the pre-operation callbacks.
        //

        Status = FsFilterPerformCallbacks( &FsFilterCtrl,
                                           FALSE,
                                           FALSE,
                                           &BaseFsFailedOperation );
    }

    if (Status == STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY) {

        //
        //  The filter/file system completed the operation, therefore we just need to
        //  call the completion callbacks for this operation.  There is no need to try
        //  to call the base file system.
        //

        Status = STATUS_SUCCESS;

    } else if (NT_SUCCESS( Status )) {

        if (CallFilters) {

            //
            // Always copy out file object
            //

            FileObject = FsFilterCtrl.Data.FileObject;

            if (FlagOn( FsFilterCtrl.Flags, FS_FILTER_CHANGED_DEVICE_STACKS )) {

                BaseFsDeviceObject = IoGetDeviceAttachmentBaseRef( FsFilterCtrl.Data.DeviceObject );
                ReleaseBaseFsDeviceReference = TRUE;
                FastIoDispatch = GET_FAST_IO_DISPATCH( BaseFsDeviceObject );
                FsFilterCallbacks = GET_FS_FILTER_CALLBACKS( BaseFsDeviceObject );
            }
        }

        if (!(VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PreReleaseForSectionSynchronization ) ||
              VALID_FS_FILTER_CALLBACK_HANDLER( FsFilterCallbacks, PostReleaseForSectionSynchronization ))) {

            //
            //  Call the base file system.
            //

            if (VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatch,
                                                ReleaseFileForNtCreateSection )) {

                FastIoDispatch->ReleaseFileForNtCreateSection( FileObject );

                //
                //  The status should already be STATUS_SUCCESS if we come down
                //  this path.  Since the FastIo handler doesn't return a value
                //  the status should remain STATUS_SUCCESS.
                //

                //  Status = STATUS_SUCCESS;

            } else {

                Status = STATUS_INVALID_DEVICE_REQUEST;
            }

            //
            //  If there is a failure at this point, we know that the failure
            //  was caused by the base file system.
            //

            BaseFsFailedOperation = TRUE;
        }

        if (ReleaseBaseFsDeviceReference) {

            ObDereferenceObject( BaseFsDeviceObject );
        }
    }

    ASSERT( (Status == STATUS_SUCCESS) ||
            (Status == STATUS_INVALID_DEVICE_REQUEST ) );

    if (Status == STATUS_INVALID_DEVICE_REQUEST &&
        BaseFsFailedOperation) {

        PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext;

        //
        //  The base file system doesn't provide a handler for this
        //  operation, so perform the default actions.
        //

        //
        //  If there is a main file resource, release that.
        //

        if ((Header != NULL) && (Header->Resource != NULL)) {

            ExReleaseResourceLite( Header->Resource );
        }

        Status = STATUS_SUCCESS;
    }

    //
    //  Again, we only want to call try to do completion callbacks
    //  if there are any filters attached to this device that have
    //  completion callbacks.  In any case, if we called down to the filters
    //  we need to free the FsFilterCtrl.
    //

    if (CallFilters) {

        if (FS_FILTER_HAVE_COMPLETIONS( CallFilters )) {

            FsFilterPerformCompletionCallbacks( &FsFilterCtrl, Status );
        }

        FsFilterCtrlFree( &FsFilterCtrl );
    }

    FsRtlExitFileSystem();

    return;
}


NTSTATUS
FsRtlGetFileSize(
    __in PFILE_OBJECT FileObject,
    __inout PLARGE_INTEGER FileSize
    )

/*++

Routine Description:

    This routine is used to call the File System to get the FileSize
    for a file.

    It does this without acquiring the file object lock on synchronous file
    objects.  This routine is therefore safe to call if you already own
    file system resources, while IoQueryFileInformation could (and does)
    lead to deadlocks.

Arguments:

    FileObject - The file to query
    FileSize - Receives the file size.

Return Value:

    NTSTATUS - The final I/O status of the operation.  If the FileObject
        refers to a directory, STATUS_FILE_IS_A_DIRECTORY is returned.

--*/
{
    IO_STATUS_BLOCK IoStatus;
    PDEVICE_OBJECT DeviceObject;
    PFAST_IO_DISPATCH FastIoDispatch;
    FILE_STANDARD_INFORMATION FileInformation;

    PAGED_CODE();

    //
    // Get the address of the target device object.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );

    //
    // Try the fast query call if it exists.
    //

    FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;

    if (FastIoDispatch &&
        FastIoDispatch->FastIoQueryStandardInfo &&
        FastIoDispatch->FastIoQueryStandardInfo( FileObject,
                                                 TRUE,
                                                 &FileInformation,
                                                 &IoStatus,
                                                 DeviceObject )) {
        //
        //  Cool, it worked.
        //

    } else {

        //
        //  Life's tough, take the long path.
        //

        PIRP Irp;
        KEVENT Event;
        NTSTATUS Status;
        PIO_STACK_LOCATION IrpSp;
        BOOLEAN HardErrorState;

        //
        //  Initialize the event.
        //

        KeInitializeEvent( &Event, NotificationEvent, FALSE );

        //
        //  Allocate an I/O Request Packet (IRP) for this in-page operation.
        //

        Irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
        if (Irp == NULL) {

            return STATUS_INSUFFICIENT_RESOURCES;
        }

        //
        //  Disable hard errors over this call. Caller owns resources, is in a critical
        //  region and cannot complete hard error APCs.
        //

        HardErrorState = IoSetThreadHardErrorMode( FALSE );

        //
        //  Get a pointer to the first stack location in the packet.  This location
        //  will be used to pass the function codes and parameters to the first
        //  driver.
        //

        IrpSp = IoGetNextIrpStackLocation( Irp );

        //
        //  Fill in the IRP according to this request, setting the flags to
        //  just cause IO to set the event and deallocate the Irp.
        //

        Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO;
        Irp->RequestorMode = KernelMode;
        Irp->UserIosb = &IoStatus;
        Irp->UserEvent = &Event;
        Irp->Tail.Overlay.OriginalFileObject = FileObject;
        Irp->Tail.Overlay.Thread = PsGetCurrentThread();
        Irp->AssociatedIrp.SystemBuffer = &FileInformation;

        //
        //  Fill in the normal query parameters.
        //

        IrpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
        IrpSp->FileObject = FileObject;
        IrpSp->DeviceObject = DeviceObject;
        IrpSp->Parameters.SetFile.Length = sizeof(FILE_STANDARD_INFORMATION);
        IrpSp->Parameters.SetFile.FileInformationClass = FileStandardInformation;

        //
        //  Queue the packet to the appropriate driver based.  This routine
        //  should not raise.
        //

        Status = IoCallDriver( DeviceObject, Irp );

        //
        //  If pending is returned (which is a successful status),
        //  we must wait for the request to complete.
        //

        if (Status == STATUS_PENDING) {
            KeWaitForSingleObject( &Event,
                                   Executive,
                                   KernelMode,
                                   FALSE,
                                   (PLARGE_INTEGER)NULL);
        }

        //
        //  If we got an error back in Status, then the Iosb
        //  was not written, so we will just copy the status
        //  there, then test the final status after that.
        //

        if (!NT_SUCCESS(Status)) {
            IoStatus.Status = Status;
        }

        //
        //  Reset the hard error state.
        //

        IoSetThreadHardErrorMode( HardErrorState );
    }

    //
    //  If the call worked, check to make sure it wasn't a directory and
    //  if not, fill in the FileSize parameter.
    //

    if (NT_SUCCESS(IoStatus.Status)) {

        if (FileInformation.Directory) {

            //
            // Can't get file size for a directory. Return error.
            //

            IoStatus.Status = STATUS_FILE_IS_A_DIRECTORY;

        } else {

            *FileSize = FileInformation.EndOfFile;
        }
    }

    return IoStatus.Status;
}


NTSTATUS
FsRtlSetFileSize(
    IN PFILE_OBJECT FileObject,
    IN OUT PLARGE_INTEGER FileSize
    )

/*++

Routine Description:

    This routine is used to call the File System to update FileSize
    for a file.

    It does this without acquiring the file object lock on synchronous file
    objects.  This routine is therefore safe to call if you already own
    file system resources, while IoSetInformation could (and does) lead
    to deadlocks.

Arguments:

    FileObject - A pointer to a referenced file object.

    ValidDataLength - Pointer to new FileSize.

Return Value:

    Status of operation.

--*/

{
    PIO_STACK_LOCATION IrpSp;
    PDEVICE_OBJECT DeviceObject;
    NTSTATUS Status;
    FILE_END_OF_FILE_INFORMATION Buffer;
    IO_STATUS_BLOCK IoStatus;
    KEVENT Event;
    PIRP Irp;
    BOOLEAN HardErrorState;

    PAGED_CODE();

    //
    //  Copy FileSize to our buffer.
    //

    Buffer.EndOfFile = *FileSize;

    //
    //  Initialize the event.
    //

    KeInitializeEvent( &Event, NotificationEvent, FALSE );

    //
    //  Begin by getting a pointer to the device object that the file resides
    //  on.
    //

    DeviceObject = IoGetRelatedDeviceObject( FileObject );

    //
    //  Allocate an I/O Request Packet (IRP) for this in-page operation.
    //

    Irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
    if (Irp == NULL) {

        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    //  Disable hard errors over this call. Caller owns resources, is in a critical
    //  region and cannot complete hard error APCs.
    //

    HardErrorState = IoSetThreadHardErrorMode( FALSE );

    //
    //  Get a pointer to the first stack location in the packet.  This location
    //  will be used to pass the function codes and parameters to the first
    //  driver.
    //

    IrpSp = IoGetNextIrpStackLocation( Irp );

    //
    //  Fill in the IRP according to this request, setting the flags to
    //  just cause IO to set the event and deallocate the Irp.
    //

    Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO;
    Irp->RequestorMode = KernelMode;
    Irp->UserIosb = &IoStatus;
    Irp->UserEvent = &Event;
    Irp->Tail.Overlay.OriginalFileObject = FileObject;
    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
    Irp->AssociatedIrp.SystemBuffer = &Buffer;

    //
    //  Fill in the normal set file parameters.
    //

    IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
    IrpSp->FileObject = FileObject;
    IrpSp->DeviceObject = DeviceObject;
    IrpSp->Parameters.SetFile.Length = sizeof(FILE_END_OF_FILE_INFORMATION);
    IrpSp->Parameters.SetFile.FileInformationClass = FileEndOfFileInformation;

    //
    //  Queue the packet to the appropriate driver based on whether or not there
    //  is a VPB associated with the device.  This routine should not raise.
    //

    Status = IoCallDriver( DeviceObject, Irp );

    //
    //  If pending is returned (which is a successful status),
    //  we must wait for the request to complete.
    //

    if (Status == STATUS_PENDING) {
        KeWaitForSingleObject( &Event,
                               Executive,
                               KernelMode,
                               FALSE,
                               (PLARGE_INTEGER)NULL);
    }

    //
    //  If we got an error back in Status, then the Iosb
    //  was not written, so we will just copy the status
    //  there, then test the final status after that.
    //

    if (!NT_SUCCESS(Status)) {
        IoStatus.Status = Status;
    }

    //
    //  Reset the hard error state.
    //

    IoSetThreadHardErrorMode( HardErrorState );

    return IoStatus.Status;
}


VOID
FsRtlIncrementCcFastReadNotPossible( VOID )

/*++

Routine Description:

    This routine increments the CcFastReadNotPossible counter in the PRCB

Arguments:

Return Value:

--*/

{
    HOT_STATISTIC( CcFastReadNotPossible ) += 1;
}


VOID
FsRtlIncrementCcFastReadWait( VOID )

/*++

Routine Description:

    This routine increments the CcFastReadWait counter in the PRCB

Arguments:

Return Value:

--*/

{

    HOT_STATISTIC(CcFastReadWait) += 1;
}


VOID
FsRtlIncrementCcFastReadNoWait( VOID )

/*++

Routine Description:

    This routine increments the CcFastReadNoWait counter in the PRCB

Arguments:

Return Value:

--*/

{

    HOT_STATISTIC(CcFastReadNoWait) += 1;
}


VOID
FsRtlIncrementCcFastReadResourceMiss( VOID )

/*++

Routine Description:

    This routine increments the CcFastReadResourceMiss

Arguments:

Return Value:

--*/

{

    CcFastReadResourceMiss += 1;
}

