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

📄 write.c

📁 winddk src目录下的文件系统驱动源码压缩!
💻 C
📖 第 1 页 / 共 5 页
字号:
    ASSERT( Vcb != NULL );

    //
    //  Save callers who try to do cached IO to the raw volume from themselves.
    //

    if (TypeOfOpen == UserVolumeOpen) {

        NonCachedIo = TRUE;
    }

    ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile));

    //
    //  Collect interesting statistics.  The FLAG_USER_IO bit will indicate
    //  what type of io we're doing in the FatNonCachedIo function.
    //

    if (PagingIo) {
        CollectWriteStats(Vcb, TypeOfOpen, ByteCount);

        if (TypeOfOpen == UserFileOpen) {
            SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        } else {
            ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
        }
    }

    //
    //  We must disallow writes to regular objects that would require us
    //  to maintain an AllocationSize of greater than 32 significant bits.
    //
    //  If this is paging IO, this is simply a case where we need to trim.
    //  This will occur in due course.
    //

    if (!PagingIo && !WriteToEof && (TypeOfOpen != UserVolumeOpen)) {

        if (!FatIsIoRangeValid( Vcb, StartingByte, ByteCount )) {

            Irp->IoStatus.Information = 0;
            FatCompleteRequest( IrpContext, Irp, STATUS_DISK_FULL );

            return STATUS_DISK_FULL;
        }
    }

    //
    //  Allocate if necessary and initialize a FAT_IO_CONTEXT block for
    //  all non cached Io.  For synchronous Io
    //  we use stack storage, otherwise we allocate pool.
    //

    if (NonCachedIo) {

        if (IrpContext->FatIoContext == NULL) {

            if (!Wait) {

                IrpContext->FatIoContext =
                    FsRtlAllocatePoolWithTag( NonPagedPool,
                                              sizeof(FAT_IO_CONTEXT),
                                              TAG_FAT_IO_CONTEXT );

            } else {

                IrpContext->FatIoContext = &StackFatIoContext;

                SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
            }
        }

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

        if (Wait) {

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

        } else {

            IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
                ExGetCurrentResourceThread();

            IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
                ByteCount;

            IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
        }
    }

    //
    //  Check if this volume has already been shut down.  If it has, fail
    //  this write request.
    //

    if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ) {

        Irp->IoStatus.Information = 0;
        FatCompleteRequest( IrpContext, Irp, STATUS_TOO_LATE );
        return STATUS_TOO_LATE;
    }

    //
    //  This case corresponds to a write of the volume file (only the first
    //  fat allowed, the other fats are written automatically in parallel).
    //
    //  We use an Mcb keep track of dirty sectors.  Actual entries are Vbos
    //  and Lbos (ie. bytes), though they are all added in sector chunks.
    //  Since Vbo == Lbo for the volume file, the Mcb entries
    //  alternate between runs of Vbo == Lbo, and holes (Lbo == 0).  We use
    //  the prior to represent runs of dirty fat sectors, and the latter
    //  for runs of clean fat.  Note that since the first part of the volume
    //  file (boot sector) is always clean (a hole), and an Mcb never ends in
    //  a hole, there must always be an even number of runs(entries) in the Mcb.
    //
    //  The strategy is to find the first and last dirty run in the desired
    //  write range (which will always be a set of pages), and write from the
    //  former to the later.  The may result in writing some clean data, but
    //  will generally be more efficient than writing each runs seperately.
    //

    if (TypeOfOpen == VirtualVolumeFile) {

        LBO DirtyLbo;
        LBO CleanLbo;

        VBO DirtyVbo;
        VBO StartingDirtyVbo;

        ULONG DirtyByteCount;
        ULONG CleanByteCount;

        ULONG WriteLength;

        BOOLEAN MoreDirtyRuns = TRUE;

        IO_STATUS_BLOCK RaiseIosb;

        DebugTrace(0, Dbg, "Type of write is Virtual Volume File\n", 0);

        //
        //  If we can't wait we have to post this.
        //

        if (!Wait) {

            DebugTrace( 0, Dbg, "Passing request to Fsp\n", 0 );

            Status = FatFsdPostRequest(IrpContext, Irp);

            return Status;
        }

        //
        //  If we weren't called by the Lazy Writer, then this write
        //  must be the result of a write-through or flush operation.
        //  Setting the IrpContext flag, will cause DevIoSup.c to
        //  write-through the data to the disk.
        //

        if (!FlagOn((ULONG_PTR)IoGetTopLevelIrp(), FSRTL_CACHE_TOP_LEVEL_IRP)) {

            SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
        }

        //
        //  Assert an even number of entries in the Mcb, an odd number would
        //  mean that the Mcb is corrupt.
        //

        ASSERT( (FsRtlNumberOfRunsInLargeMcb( &Vcb->DirtyFatMcb ) & 1) == 0);

        //
        //  We need to skip over any clean sectors at the start of the write.
        //
        //  Also check the two cases where there are no dirty fats in the
        //  desired write range, and complete them with success.
        //
        //      1) There is no Mcb entry corresponding to StartingVbo, meaning
        //         we are beyond the end of the Mcb, and thus dirty fats.
        //
        //      2) The run at StartingVbo is clean and continues beyond the
        //         desired write range.
        //

        if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
                                StartingVbo,
                                &DirtyLbo,
                                &DirtyByteCount,
                                NULL )

          || ( (DirtyLbo == 0) && (DirtyByteCount >= ByteCount) ) ) {

            DebugTrace(0, DEBUG_TRACE_DEBUG_HOOKS,
                       "No dirty fat sectors in the write range.\n", 0);

            FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
            return STATUS_SUCCESS;
        }

        DirtyVbo = (VBO)DirtyLbo;

        //
        //  If the last run was a hole (clean), up DirtyVbo to the next
        //  run, which must be dirty.
        //

        if (DirtyVbo == 0) {

            DirtyVbo = StartingVbo + DirtyByteCount;
        }

        //
        //  This is where the write will start.
        //

        StartingDirtyVbo = DirtyVbo;

        //
        //
        //  Now start enumerating the dirty fat sectors spanning the desired
        //  write range, this first one of which is now DirtyVbo.
        //

        while ( MoreDirtyRuns ) {

            //
            //  Find the next dirty run, if it is not there, the Mcb ended
            //  in a hole, or there is some other corruption of the Mcb.
            //

            if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
                                    DirtyVbo,
                                    &DirtyLbo,
                                    &DirtyByteCount,
                                    NULL )) {

                DirtyVbo = (VBO)DirtyLbo;

                DebugTrace(0, Dbg, "Last dirty fat Mcb entry was a hole: corrupt.\n", 0);
                FatBugCheck( 0, 0, 0 );

            } else {

                DirtyVbo = (VBO)DirtyLbo;

                //
                //  This has to correspond to a dirty run, and must start
                //  within the write range since we check it at entry to,
                //  and at the bottom of this loop.
                //

                ASSERT((DirtyVbo != 0) && (DirtyVbo < StartingVbo + ByteCount));

                //
                //  There are three ways we can know that this was the
                //  last dirty run we want to write.
                //
                //      1)  The current dirty run extends beyond or to the
                //          desired write range.
                //
                //      2)  On trying to find the following clean run, we
                //          discover that this is the last run in the Mcb.
                //
                //      3)  The following clean run extend beyond the
                //          desired write range.
                //
                //  In any of these cases we set MoreDirtyRuns = FALSE.
                //

                //
                //  If the run is larger than we are writing, we also
                //  must truncate the WriteLength.  This is benign in
                //  the equals case.
                //

                if (DirtyVbo + DirtyByteCount >= StartingVbo + ByteCount) {

                    DirtyByteCount = StartingVbo + ByteCount - DirtyVbo;

                    MoreDirtyRuns = FALSE;

                } else {

                    //
                    //  Scan the clean hole after this dirty run.  If this
                    //  run was the last, prepare to exit the loop
                    //

                    if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
                                            DirtyVbo + DirtyByteCount,
                                            &CleanLbo,
                                            &CleanByteCount,
                                            NULL )) {

                        MoreDirtyRuns = FALSE;

                    } else {

                        //
                        //  Assert that we actually found a clean run.
                        //  and compute the start of the next dirty run.
                        //

                        ASSERT (CleanLbo == 0);

                        //
                        //  If the next dirty run starts beyond the desired
                        //  write, we have found all the runs we need, so
                        //  prepare to exit.
                        //

                        if (DirtyVbo + DirtyByteCount + CleanByteCount >=
                                                    StartingVbo + ByteCount) {

                            MoreDirtyRuns = FALSE;

                        } else {

                            //
                            //  Compute the start of the next dirty run.
                            //

                            DirtyVbo += DirtyByteCount + CleanByteCount;
                        }
                    }
                }
            }
        } // while ( MoreDirtyRuns )

        //
        //  At this point DirtyVbo and DirtyByteCount correctly reflect the
        //  final dirty run, constrained to the desired write range.
        //
        //  Now compute the length we finally must write.
        //

        WriteLength = (DirtyVbo + DirtyByteCount) - StartingDirtyVbo;

        //
        // We must now assume that the write will complete with success,
        // and initialize our expected status in RaiseIosb.  It will be
        // modified below if an error occurs.
        //

        RaiseIosb.Status = STATUS_SUCCESS;
        RaiseIosb.Information = ByteCount;

        //
        //  Loop through all the fats, setting up a multiple async to
        //  write them all.  If there are more than FAT_MAX_PARALLEL_IOS
        //  then we do several muilple asyncs.
        //

        {
            ULONG Fat;
            ULONG BytesPerFat;
            IO_RUN StackIoRuns[2];
            PIO_RUN IoRuns;

            BytesPerFat = FatBytesPerFat( &Vcb->Bpb );

            if ((ULONG)Vcb->Bpb.Fats > 2) {

                IoRuns = FsRtlAllocatePoolWithTag( PagedPool,
                                                   (ULONG)Vcb->Bpb.Fats,
                                                   TAG_IO_RUNS );

            } else {

                IoRuns = StackIoRuns;
            }

⌨️ 快捷键说明

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