Exemplo n.º 1
0
LARGE_INTEGER
CcGetDirtyPages (
    __in PVOID LogHandle,
    __in PDIRTY_PAGE_ROUTINE DirtyPageRoutine,
    __in PVOID Context1,
    __in PVOID Context2
    )

/*++

Routine Description:

    This routine may be called to return all of the dirty pages in all files
    for a given log handle.  Each page is returned by an individual call to
    the Dirty Page Routine.  The Dirty Page Routine is defined by a prototype
    in ntos\inc\cache.h.

Arguments:

    LogHandle - Log Handle which must match the log handle previously stored
                for all files which are to be returned.

    DirtyPageRoutine -- The routine to call as each dirty page for this log
                        handle is found.

    Context1 - First context parameter to be passed to the Dirty Page Routine.

    Context2 - First context parameter to be passed to the Dirty Page Routine.

Return Value:

    LARGE_INTEGER - Oldest Lsn found of all the dirty pages, or 0 if no dirty pages

--*/

{
    PSHARED_CACHE_MAP SharedCacheMap;
    PBCB Bcb, BcbToUnpin = NULL;
    KLOCK_QUEUE_HANDLE LockHandle;
    LARGE_INTEGER SavedFileOffset, SavedOldestLsn, SavedNewestLsn;
    ULONG SavedByteLength;
    LARGE_INTEGER OldestLsn = {0,0};

    //
    //  Synchronize with changes to the SharedCacheMap list.
    //

    CcAcquireMasterLock( &LockHandle.OldIrql );

    SharedCacheMap = CONTAINING_RECORD( CcDirtySharedCacheMapList.SharedCacheMapLinks.Flink,
                                        SHARED_CACHE_MAP,
                                        SharedCacheMapLinks );

    //
    //  Use try/finally for cleanup.  The only spot where we can raise is out of the
    //  filesystem callback, but we have the exception handler out here so we aren't
    //  constantly setting/unsetting it.
    //

    try {

        while (&SharedCacheMap->SharedCacheMapLinks != &CcDirtySharedCacheMapList.SharedCacheMapLinks) {

            //
            //  Skip over cursors, SharedCacheMaps for other LogHandles, and ones with
            //  no dirty pages
            //

            if (!FlagOn(SharedCacheMap->Flags, IS_CURSOR) && (SharedCacheMap->LogHandle == LogHandle) &&
                (SharedCacheMap->DirtyPages != 0)) {

                //
                //  This SharedCacheMap should stick around for a while in the dirty list.
                //

                CcIncrementOpenCount( SharedCacheMap, 'pdGS' );
                SharedCacheMap->DirtyPages += 1;
                CcReleaseMasterLock( LockHandle.OldIrql );

                //
                //  Set our initial resume point and point to first Bcb in List.
                //

                KeAcquireInStackQueuedSpinLock( &SharedCacheMap->BcbSpinLock, &LockHandle );
                Bcb = CONTAINING_RECORD( SharedCacheMap->BcbList.Flink, BCB, BcbLinks );

                //
                //  Scan to the end of the Bcb list.
                //

                while (&Bcb->BcbLinks != &SharedCacheMap->BcbList) {

                    //
                    //  If the Bcb is dirty, then capture the inputs for the
                    //  callback routine so we can call without holding a spinlock.
                    //

                    if ((Bcb->NodeTypeCode == CACHE_NTC_BCB) && Bcb->Dirty) {

                        SavedFileOffset = Bcb->FileOffset;
                        SavedByteLength = Bcb->ByteLength;
                        SavedOldestLsn = Bcb->OldestLsn;
                        SavedNewestLsn = Bcb->NewestLsn;

                        //
                        //  Increment PinCount so the Bcb sticks around
                        //

                        Bcb->PinCount += 1;

                        KeReleaseInStackQueuedSpinLock( &LockHandle );

                        //
                        //  Any Bcb to unref from a previous loop?
                        //

                        if (BcbToUnpin != NULL) {
                            CcUnpinFileData( BcbToUnpin, TRUE, UNREF );
                            BcbToUnpin = NULL;
                        }

                        //
                        //  Call the file system.  This callback may raise status.
                        //

                        (*DirtyPageRoutine)( SharedCacheMap->FileObject,
                                             &SavedFileOffset,
                                             SavedByteLength,
                                             &SavedOldestLsn,
                                             &SavedNewestLsn,
                                             Context1,
                                             Context2 );

                        //
                        //  Possibly update OldestLsn
                        //

                        if ((SavedOldestLsn.QuadPart != 0) &&
                            ((OldestLsn.QuadPart == 0) || (SavedOldestLsn.QuadPart < OldestLsn.QuadPart ))) {
                            OldestLsn = SavedOldestLsn;
                        }

                        //
                        //  Now reacquire the spinlock and scan from the resume point
                        //  point to the next Bcb to return in the descending list.
                        //

                        KeAcquireInStackQueuedSpinLock( &SharedCacheMap->BcbSpinLock, &LockHandle );

                        //
                        //  Normally the Bcb can stay around a while, but if not,
                        //  we will just remember it for the next time we do not
                        //  have the spin lock.  We cannot unpin it now, because
                        //  we would lose our place in the list.
                        //
                        //  This is cheating, but it works and is sane since we're
                        //  already traversing the bcb list - dropping the bcb count
                        //  is OK, as long as we don't hit zero.  Zero requires a 
                        //  slight bit more attention that shouldn't be replicated.
                        //  (unmapping the view)
                        //

                        if (Bcb->PinCount > 1) {
                            Bcb->PinCount -= 1;
                        } else {
                            BcbToUnpin = Bcb;
                        }
                    }

                    Bcb = CONTAINING_RECORD( Bcb->BcbLinks.Flink, BCB, BcbLinks );
                }
                KeReleaseInStackQueuedSpinLock( &LockHandle );

                //
                //  We need to unref any Bcb we are holding before moving on to
                //  the next SharedCacheMap, or else CcDeleteSharedCacheMap will
                //  also delete this Bcb.
                //

                if (BcbToUnpin != NULL) {

                    CcUnpinFileData( BcbToUnpin, TRUE, UNREF );
                    BcbToUnpin = NULL;
                }

                CcAcquireMasterLock( &LockHandle.OldIrql );

                //
                //  Now release the SharedCacheMap, leaving it in the dirty list.
                //

                CcDecrementOpenCount( SharedCacheMap, 'pdGF' );
                SharedCacheMap->DirtyPages -= 1;
            }

            //
            //  Now loop back for the next cache map.
            //

            SharedCacheMap =
                CONTAINING_RECORD( SharedCacheMap->SharedCacheMapLinks.Flink,
                                   SHARED_CACHE_MAP,
                                   SharedCacheMapLinks );
        }

        CcReleaseMasterLock( LockHandle.OldIrql );

    } finally {

        //
        //  Drop the Bcb if we are being ejected.  We are guaranteed that the
        //  only raise is from the callback, at which point we have an incremented
        //  pincount.
        //

        if (AbnormalTermination()) {

            CcUnpinFileData( Bcb, TRUE, UNPIN );
        }
    }

    return OldestLsn;
}
Exemplo n.º 2
0
VOID
CcMdlWriteComplete2 (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN PMDL MdlChain
    )

/*++

Routine Description:

    This routine must be called at IPL0 after a call to CcPrepareMdlWrite.
    The caller supplies the ActualLength of data that it actually wrote
    into the buffer, which may be less than or equal to the Length specified
    in CcPrepareMdlWrite.

    This call does the following:

        Makes sure the data up to ActualLength eventually gets written.
        If WriteThrough is FALSE, the data will not be written immediately.
        If WriteThrough is TRUE, then the data is written synchronously.

        Unmaps the pages (if mapped), unlocks them and deletes the MdlChain

Arguments:

    FileObject - Pointer to the file object for a file which was
                 opened with NO_INTERMEDIATE_BUFFERING clear, i.e., for
                 which CcInitializeCacheMap was called by the file system.

    FileOffset - Original file offset read above.

    MdlChain - same as returned from corresponding call to CcPrepareMdlWrite.

Return Value:

    None

--*/

{
    PMDL MdlNext;
    PSHARED_CACHE_MAP SharedCacheMap;
    LARGE_INTEGER FOffset;
    IO_STATUS_BLOCK IoStatus;
    KIRQL OldIrql;
    NTSTATUS StatusToRaise = STATUS_SUCCESS;

    DebugTrace(+1, me, "CcMdlWriteComplete\n", 0 );
    DebugTrace( 0, me, "    FileObject = %08lx\n", FileObject );
    DebugTrace( 0, me, "    MdlChain = %08lx\n", MdlChain );

    SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;

    //
    //  Deallocate the Mdls
    //

    FOffset.QuadPart = *(LONGLONG UNALIGNED *)FileOffset;
    while (MdlChain != NULL) {

        MdlNext = MdlChain->Next;

        DebugTrace( 0, mm, "MmUnlockPages/IoFreeMdl:\n", 0 );
        DebugTrace( 0, mm, "    Mdl = %08lx\n", MdlChain );

        //
        //  Now clear the dirty bits in the Pte and set them in the
        //  Pfn.
        //

        MmUnlockPages( MdlChain );

        //
        //  Extract the File Offset for this part of the transfer.
        //

        if (FlagOn(FileObject->Flags, FO_WRITE_THROUGH)) {

            MmFlushSection ( FileObject->SectionObjectPointer,
                             &FOffset,
                             MdlChain->ByteCount,
                             &IoStatus,
                             TRUE );

            //
            //  If we got an I/O error, remember it.
            //

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

        } else {

            //
            //  Ignore the only exception (allocation error), and console
            //  ourselves for having tried.
            //

            CcSetDirtyInMask( SharedCacheMap, &FOffset, MdlChain->ByteCount );
        }

        FOffset.QuadPart = FOffset.QuadPart + (LONGLONG)(MdlChain->ByteCount);

        IoFreeMdl( MdlChain );

        MdlChain = MdlNext;
    }

    //
    //  Now release our open count.
    //

    CcAcquireMasterLock( &OldIrql );

    CcDecrementOpenCount( SharedCacheMap, 'ldmC' );

    if ((SharedCacheMap->OpenCount == 0) &&
        !FlagOn(SharedCacheMap->Flags, WRITE_QUEUED) &&
        (SharedCacheMap->DirtyPages == 0)) {

        //
        //  Move to the dirty list.
        //

        RemoveEntryList( &SharedCacheMap->SharedCacheMapLinks );
        InsertTailList( &CcDirtySharedCacheMapList.SharedCacheMapLinks,
                        &SharedCacheMap->SharedCacheMapLinks );

        //
        //  Make sure the Lazy Writer will wake up, because we
        //  want him to delete this SharedCacheMap.
        //

        LazyWriter.OtherWork = TRUE;
        if (!LazyWriter.ScanActive) {
            CcScheduleLazyWriteScan();
        }
    }

    CcReleaseMasterLock( OldIrql );

    //
    //  If we got an I/O error, raise it now.
    //

    if (!NT_SUCCESS(StatusToRaise)) {
        FsRtlNormalizeNtstatus( StatusToRaise,
                                STATUS_UNEXPECTED_IO_ERROR );
    }

    DebugTrace(-1, me, "CcMdlWriteComplete -> TRUE\n", 0 );

    return;
}