Beispiel #1
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
CcWaitForCurrentLazyWriterActivity (
    VOID)
{
    KIRQL OldIrql;
    KEVENT WaitEvent;
    PWORK_QUEUE_ENTRY WorkItem;

    /* Allocate a work item */
    WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
    if (WorkItem == NULL)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    /* We want lazy writer to set our event */
    WorkItem->Function = SetDone;
    KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE);
    WorkItem->Parameters.Event.Event = &WaitEvent;

    /* Use the post tick queue */
    OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
    InsertTailList(&CcPostTickWorkQueue, &WorkItem->WorkQueueLinks);

    /* Inform the lazy writer it will have to handle the post tick queue */
    LazyWriter.OtherWork = TRUE;
    /* And if it's not running, queue a lazy writer run
     * And start it NOW, we want the response now
     */
    if (!LazyWriter.ScanActive)
    {
        CcScheduleLazyWriteScan(TRUE);
    }

    KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);

    /* And now, wait until lazy writer replies */
    return KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, NULL);
}
Beispiel #2
0
VOID
CcLazyWriteScan(VOID)
{
    ULONG Target;
    KIRQL OldIrql;
    PLIST_ENTRY ListEntry;
    LIST_ENTRY ToPost;
    PWORK_QUEUE_ENTRY WorkItem;

    /* Do we have entries to queue after we're done? */
    InitializeListHead(&ToPost);
    OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
    if (LazyWriter.OtherWork)
    {
        while (!IsListEmpty(&CcPostTickWorkQueue))
        {
            ListEntry = RemoveHeadList(&CcPostTickWorkQueue);
            WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
            InsertTailList(&ToPost, &WorkItem->WorkQueueLinks);
        }
        LazyWriter.OtherWork = FALSE;
    }
    KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);

    /* Our target is one-eighth of the dirty pages */
    Target = CcTotalDirtyPages / 8;
    if (Target != 0)
    {
        /* There is stuff to flush, schedule a write-behind operation */

        /* Allocate a work item */
        WorkItem = ExAllocateFromNPagedLookasideList(&CcTwilightLookasideList);
        if (WorkItem != NULL)
        {
            WorkItem->Function = WriteBehind;
            CcPostWorkQueue(WorkItem, &CcRegularWorkQueue);
        }
    }

    /* Post items that were due for end of run */
    while (!IsListEmpty(&ToPost))
    {
        ListEntry = RemoveHeadList(&ToPost);
        WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ENTRY, WorkQueueLinks);
        CcPostWorkQueue(WorkItem, &CcRegularWorkQueue);
    }

    /* If we have deferred writes, try them now! */
    if (!IsListEmpty(&CcDeferredWrites))
    {
        CcPostDeferredWrites();
        /* Reschedule immediately a lazy writer run
         * Keep us active to have short idle delay
         */
        CcScheduleLazyWriteScan(FALSE);
    }
    else
    {
        /* We're no longer active */
        OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock);
        LazyWriter.ScanActive = FALSE;
        KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql);
    }
}
Beispiel #3
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;
}