⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 write.c

📁 winddk src目录下的文件系统驱动源码压缩!
💻 C
📖 第 1 页 / 共 5 页
字号:
            ASSERT( WriteToEof ? !PagingIo : TRUE );
            
            //
            //  First let's acquire the Fcb shared.  Shared is enough if we
            //  are not writing beyond EOF.
            //

            if ( PagingIo ) {

                (VOID)ExAcquireResourceSharedLite( FcbOrDcb->Header.PagingIoResource, TRUE );
                PagingIoResourceAcquired = TRUE;

                if (!Wait) {

                    IrpContext->FatIoContext->Wait.Async.Resource =
                        FcbOrDcb->Header.PagingIoResource;
                }

                //
                //  Check to see if we colided with a MoveFile call, and if
                //  so block until it completes.
                //

                if (FcbOrDcb->MoveFileEvent) {

                    (VOID)KeWaitForSingleObject( FcbOrDcb->MoveFileEvent,
                                                 Executive,
                                                 KernelMode,
                                                 FALSE,
                                                 NULL );
                }

            } else {

                //
                //  We may already have the Fcb due to noncached coherency
                //  work done just above; however, we may still have to extend
                //  valid data length.  We can't demote this to shared, matching
                //  what occured before, until we figure that out a bit later. 
                //
                //  We kept ahold of it since our lockorder is main->paging,
                //  and paging must now held across the noncached write from
                //  the purge on.
                //
                
                //
                //  If this is async I/O, we will wait if there is an exclusive
                //  waiter.
                //

                if (!Wait && NonCachedIo) {

                    if (!FcbOrDcbAcquired &&
                        !FatAcquireSharedFcbWaitForEx( IrpContext, FcbOrDcb )) {

                        DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %08lx shared without waiting\n", FcbOrDcb );
                        try_return( PostIrp = TRUE );
                    }

                    //
                    //  Note we will have to release this resource elsewhere.  If we came
                    //  out of the noncached coherency path, we will also have to drop
                    //  the paging io resource.
                    //

                    IrpContext->FatIoContext->Wait.Async.Resource = FcbOrDcb->Header.Resource;

                    if (FcbCanDemoteToShared) {
                        
                        IrpContext->FatIoContext->Wait.Async.Resource2 = FcbOrDcb->Header.PagingIoResource;
                    }
                } else {

                    if (!FcbOrDcbAcquired &&
                        !FatAcquireSharedFcb( IrpContext, FcbOrDcb )) {

                        DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %08lx shared without waiting\n", FcbOrDcb );
                        try_return( PostIrp = TRUE );
                    }
                }

                FcbOrDcbAcquired = TRUE;
            }

            //
            //  Get a first tentative file size and valid data length.
            //  We must get ValidDataLength first since it is always
            //  increased second (in case we are unprotected) and
            //  we don't want to capture ValidDataLength > FileSize.
            //

            ValidDataToDisk = FcbOrDcb->ValidDataToDisk;
            ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
            FileSize = FcbOrDcb->Header.FileSize.LowPart;

            ASSERT( ValidDataLength <= FileSize );

            //
            // If are paging io, then we do not want
            // to write beyond end of file.  If the base is beyond Eof, we will just
            // Noop the call.  If the transfer starts before Eof, but extends
            // beyond, we will truncate the transfer to the last sector
            // boundary.
            //

            //
            //  Just in case this is paging io, limit write to file size.
            //  Otherwise, in case of write through, since Mm rounds up
            //  to a page, we might try to acquire the resource exclusive
            //  when our top level guy only acquired it shared. Thus, =><=.
            //

            if ( PagingIo ) {

                if (StartingVbo >= FileSize) {

                    DebugTrace( 0, Dbg, "PagingIo started beyond EOF.\n", 0 );

                    Irp->IoStatus.Information = 0;

                    try_return( Status = STATUS_SUCCESS );
                }

                if (ByteCount > FileSize - StartingVbo) {

                    DebugTrace( 0, Dbg, "PagingIo extending beyond EOF.\n", 0 );

                    ByteCount = FileSize - StartingVbo;
                }
            }

            //
            //  Determine if we were called by the lazywriter.
            //  (see resrcsup.c)
            //

            if (FcbOrDcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread()) {

                CalledByLazyWriter = TRUE;

                if (FlagOn( FcbOrDcb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE )) {

                    //
                    //  Fail if the start of this request is beyond valid data length.
                    //  Don't worry if this is an unsafe test.  MM and CC won't
                    //  throw this page away if it is really dirty.
                    //

                    if ((StartingVbo + ByteCount > ValidDataLength) &&
                        (StartingVbo < FileSize)) {

                        //
                        //  It's OK if byte range is within the page containing valid data length,
                        //  since we will use ValidDataToDisk as the start point.
                        //

                        if (StartingVbo + ByteCount > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {

                            //
                            //  Don't flush this now.
                            //

                            try_return( Status = STATUS_FILE_LOCK_CONFLICT );
                        }
                    }
                }
            }

            //
            //  This code detects if we are a recursive synchronous page write
            //  on a write through file object.
            //

            if (FlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) &&
                FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL)) {

                PIRP TopIrp;

                TopIrp = IoGetTopLevelIrp();

                //
                //  This clause determines if the top level request was
                //  in the FastIo path.  Gack.  Since we don't have a
                //  real sharing protocol for the top level IRP field ...
                //  yet ... if someone put things other than a pure IRP in
                //  there we best be careful.
                //

                if ((ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG &&
                    NodeType(TopIrp) == IO_TYPE_IRP) {

                    PIO_STACK_LOCATION IrpStack;

                    IrpStack = IoGetCurrentIrpStackLocation(TopIrp);

                    //
                    //  Finally this routine detects if the Top irp was a
                    //  write to this file and thus we are the writethrough.
                    //

                    if ((IrpStack->MajorFunction == IRP_MJ_WRITE) &&
                        (IrpStack->FileObject->FsContext == FileObject->FsContext)) {

                        RecursiveWriteThrough = TRUE;
                        SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
                    }
                }
            }

            //
            //  Here is the deal with ValidDataLength and FileSize:
            //
            //  Rule 1: PagingIo is never allowed to extend file size.
            //
            //  Rule 2: Only the top level requestor may extend Valid
            //          Data Length.  This may be paging IO, as when a
            //          a user maps a file, but will never be as a result
            //          of cache lazy writer writes since they are not the
            //          top level request.
            //
            //  Rule 3: If, using Rules 1 and 2, we decide we must extend
            //          file size or valid data, we take the Fcb exclusive.
            //

            //
            // Now see if we are writing beyond valid data length, and thus
            // maybe beyond the file size.  If so, then we must
            // release the Fcb and reacquire it exclusive.  Note that it is
            // important that when not writing beyond EOF that we check it
            // while acquired shared and keep the FCB acquired, in case some
            // turkey truncates the file.
            //

            //
            //  Note that the lazy writer must not be allowed to try and
            //  acquire the resource exclusive.  This is not a problem since
            //  the lazy writer is paging IO and thus not allowed to extend
            //  file size, and is never the top level guy, thus not able to
            //  extend valid data length.
            //

            if ( !CalledByLazyWriter &&

                 !RecursiveWriteThrough &&

                 (WriteToEof ||
                  StartingVbo + ByteCount > ValidDataLength)) {

                //
                //  If this was an asynchronous write, we are going to make
                //  the request synchronous at this point, but only kinda.
                //  At the last moment, before sending the write off to the
                //  driver, we may shift back to async.
                //
                //  The modified page writer already has the resources
                //  he requires, so this will complete in small finite
                //  time.
                //

                if (!Wait) {

                    Wait = TRUE;
                    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );

                    if (NonCachedIo) {

                        ASSERT( TypeOfOpen == UserFileOpen );

                        SwitchBackToAsync = TRUE;
                    }
                }

                //
                // We need Exclusive access to the Fcb/Dcb since we will
                // probably have to extend valid data and/or file.
                //

                //
                //  Y'know, the PagingIo case is a mapped page writer, and
                //  MmFlushSection or the mapped page writer itself already
                //  snatched up the main exclusive for us via the AcquireForCcFlush
                //  or AcquireForModWrite logic (the default logic parallels FAT's
                //  requirements since this order/model came first).  Should ASSERT
                //  this since it'll just go 1->2, and a few more unnecesary DPC
                //  transitions.
                //
                //  The preacquire is done to avoid inversion over the collided flush
                //  meta-resource in Mm.  The one time this is not true is at final
                //  system shutdown time, when Mm goes off and flushes all the dirty
                //  pages.  Since the callback is defined as Wait == FALSE he can't
                //  guarantee acquisition (though with clean process shutdown being
                //  enforced, it really should be now).  Permit this to float.
                //
                //  Note that since we're going to fall back on the acquisition aleady
                //  done for us, don't confuse things by thinking we did the work
                //  for it.
                //

                if ( PagingIo ) {

                    ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
                    PagingIoResourceAcquired = FALSE;

                } else {

                    //
                    //  The Fcb may already be acquired exclusive due to coherency
                    //  work performed earlier.  If so, obviously no work to do.
                    //
                    
                    if (!FcbAcquiredExclusive) {
                        
                        FatReleaseFcb( IrpContext, FcbOrDcb );
                        FcbOrDcbAcquired = FALSE;

                        if (!FatAcquireExclusiveFcb( IrpContext, FcbOrDcb )) {

                            DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %08lx shared without waiting\n", FcbOrDcb );

                            try_return( PostIrp = TRUE );
                        }
                        
                        FcbOrDcbAcquired = TRUE;
                        FcbAcquiredExclusive = TRUE;
                    }
                }

                //
                //  Now that we have the Fcb exclusive, see if this write
                //  qualifies for being made async again.  The key point
                //  here is that we are going to update ValidDataLength in
                //  the Fcb before returning.  We must make sure this will
                //  not cause a problem.  One thing we must do is keep out
                //  the FastIo path.
                //

                if (SwitchBackToAsync) {

                    if ((FcbOrDcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) ||
                        (StartingVbo + ByteCount > FcbOrDcb->Header.ValidDataLength.LowPart) ||
                        FatNoAsync) {

                        RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );

                        KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
                                           NotificationEvent,
                                           FALSE );

                        SwitchBackToAsync = FALSE;

                    } else {

                        if (!FcbOrDcb->NonPaged->OutstandingAsyncEvent) {

                            FcbOrDcb->NonPaged->OutstandingAsyncEvent =
                                FsRtlAllocatePoolWithTag( NonPagedPool,
                                                          sizeof(KEVENT),
                                                          TAG_EVENT );

                            KeInitializeEvent( FcbOrDcb->NonPaged->OutstandingAsyncEvent,
                                               NotificationEvent,
                                               FALSE );
                        }

                        //
                        //  If we are transitioning from 0 to 1, reset the event.
                        //

                        if (ExInterlockedAddUlong( &FcbOrDcb->NonPaged->OutstandingAsyncWrites,
                                                   1,
                                                   &FatData.GeneralSpinLock ) == 0) {

                            KeClearEvent( FcbOrDcb->NonPaged->OutstandingAsyncEvent );
                        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -