summaryrefslogblamecommitdiffstats
path: root/private/ntos/fsrtl/stackovf.c
blob: 43b4dde2875e581bc1b883e32b160c21923a02a7 (plain) (tree)




































































































































































































































































































































































































                                                                                
/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    StackOvf.c

Abstract:

    The file lock package provides a worker thread to handle
    stack overflow conditions in the file systems.  When the
    file system detects that it is near the end of its stack
    during a paging I/O read request it will post the request
    to this extra thread.

Author:

    Gary Kimura     [GaryKi]    24-Nov-1992

Revision History:

--*/

#include "FsRtlP.h"
//
// Queue object that is used to hold work queue entries and synchronize
// worker thread activity.
//

KQUEUE FsRtlWorkerQueues[2];


//
//  Local Support Routine
//

VOID
FsRtlStackOverflowRead (
    IN PVOID Context
    );

VOID
FsRtlpPostStackOverflow (
    IN PVOID Context,
    IN PKEVENT Event,
    IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine,
    IN BOOLEAN PagingFile
    );

//
// Procedure prototype for the worker thread.
//

VOID
FsRtlWorkerThread(
    IN PVOID StartContext
    );

//
//  The following type is used to store an enqueue work item
//

typedef struct _STACK_OVERFLOW_ITEM {

    WORK_QUEUE_ITEM Item;

    //
    //  This is the call back routine
    //

    PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine;

    //
    //  Here are the parameters for the call back routine
    //

    PVOID Context;
    PKEVENT Event;

} STACK_OVERFLOW_ITEM;
typedef STACK_OVERFLOW_ITEM *PSTACK_OVERFLOW_ITEM;


#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, FsRtlInitializeWorkerThread)
#endif



NTSTATUS
FsRtlInitializeWorkerThread (
    VOID
    )
{
    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE Thread;
    ULONG i;

    //
    // Create worker threads to handle normal and paging overflow reads.
    //

    InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);

    for (i=0; i < 2; i++) {

        //
        // Initialize the FsRtl stack overflow work Queue objects.
        //

        KeInitializeQueue(&FsRtlWorkerQueues[i], 0);

        if (!NT_SUCCESS(PsCreateSystemThread(&Thread,
                                             THREAD_ALL_ACCESS,
                                             &ObjectAttributes,
                                             0L,
                                             NULL,
                                             FsRtlWorkerThread,
                                             (PVOID)i))) {

            return FALSE;
        }
    }

    ZwClose( Thread );

    return TRUE;
}

VOID
FsRtlPostStackOverflow (
    IN PVOID Context,
    IN PKEVENT Event,
    IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine
    )

/*++

Routine Description:

    This routines posts a stack overflow item to the stack overflow
    thread and returns.

Arguments:

    Context - Supplies the context to pass to the stack overflow
        call back routine.  If the low order bit is set, then
        this overflow was a read to a paging file.

    Event - Supplies a pointer to an event to pass to the stack
        overflow call back routine.

    StackOverflowRoutine - Supplies the call back to use when
        processing the request in the overflow thread.

Return Value:

    None.

--*/

{
    FsRtlpPostStackOverflow( Context, Event, StackOverflowRoutine, FALSE );
    return;
}


VOID
FsRtlPostPagingFileStackOverflow (
    IN PVOID Context,
    IN PKEVENT Event,
    IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine
    )

/*++

Routine Description:

    This routines posts a stack overflow item to the stack overflow
    thread and returns.

Arguments:

    Context - Supplies the context to pass to the stack overflow
        call back routine.  If the low order bit is set, then
        this overflow was a read to a paging file.

    Event - Supplies a pointer to an event to pass to the stack
        overflow call back routine.

    StackOverflowRoutine - Supplies the call back to use when
        processing the request in the overflow thread.

Return Value:

    None.

--*/

{
    FsRtlpPostStackOverflow( Context, Event, StackOverflowRoutine, TRUE );
    return;
}


VOID
FsRtlpPostStackOverflow (
    IN PVOID Context,
    IN PKEVENT Event,
    IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine,
    IN BOOLEAN PagingFile
    )

/*++

Routine Description:

    This routines posts a stack overflow item to the stack overflow
    thread and returns.

Arguments:

    Context - Supplies the context to pass to the stack overflow
        call back routine.  If the low order bit is set, then
        this overflow was a read to a paging file.

    Event - Supplies a pointer to an event to pass to the stack
        overflow call back routine.

    StackOverflowRoutine - Supplies the call back to use when
        processing the request in the overflow thread.

    PagingFile - Indicates if the read is destined to a paging file.

Return Value:

    None.

--*/

{
    PSTACK_OVERFLOW_ITEM StackOverflowItem;

    //
    //  Allocate a stack overflow work item it will later be deallocated by
    //  the stack overflow thread
    //

    StackOverflowItem = FsRtlAllocatePool( PagingFile ?
                                           NonPagedPoolMustSucceed :
                                           NonPagedPool,
                                           sizeof(STACK_OVERFLOW_ITEM) );

    //
    //  Fill in the fields in the new item
    //

    StackOverflowItem->Context              = Context;
    StackOverflowItem->Event                = Event;
    StackOverflowItem->StackOverflowRoutine = StackOverflowRoutine;

    ExInitializeWorkItem( &StackOverflowItem->Item,
                          &FsRtlStackOverflowRead,
                          StackOverflowItem );

    //
    //  Safely add it to the overflow queue
    //

    KeInsertQueue( &FsRtlWorkerQueues[PagingFile],
                   &StackOverflowItem->Item.List );

    //
    //  And return to our caller
    //

    return;
}


//
//  Local Support Routine
//

VOID
FsRtlStackOverflowRead (
    IN PVOID Context
    )

/*++

Routine Description:

    This routine processes all of the stack overflow request posted by
    the various file systems

Arguments:

Return Value:

    None.

--*/

{
    PSTACK_OVERFLOW_ITEM StackOverflowItem;

    //
    //  Since stack overflow reads are always recursive, set the
    //  TopLevelIrp field appropriately so that recurive reads
    //  from this point will not think they are top level.
    //

    PsGetCurrentThread()->TopLevelIrp = FSRTL_FSP_TOP_LEVEL_IRP;

    //
    //  Get a pointer to the stack overflow item and then call
    //  the callback routine to do the work
    //

    StackOverflowItem = (PSTACK_OVERFLOW_ITEM)Context;

    (StackOverflowItem->StackOverflowRoutine)(StackOverflowItem->Context,
                                              StackOverflowItem->Event);

    //
    //  Deallocate the work item and then go back to the loop to
    //  to wait for another work item
    //

    ExFreePool( StackOverflowItem );

    PsGetCurrentThread()->TopLevelIrp = (ULONG)NULL;
}

VOID
FsRtlWorkerThread(
    IN PVOID StartContext
    )

{
    PLIST_ENTRY Entry;
    PWORK_QUEUE_ITEM WorkItem;
    ULONG PagingFile = (ULONG)StartContext;

    //
    //  Set our priority to low realtime, or +1 for PagingFile.
    //

    (PVOID)KeSetPriorityThread( &PsGetCurrentThread()->Tcb,
                                LOW_REALTIME_PRIORITY + PagingFile );

    //
    // Loop forever waiting for a work queue item, calling the processing
    // routine, and then waiting for another work queue item.
    //

    do {

        //
        // Wait until something is put in the queue.
        //
        // By specifying a wait mode of KernelMode, the thread's kernel stack is
        // NOT swappable
        //

        Entry = KeRemoveQueue(&FsRtlWorkerQueues[PagingFile], KernelMode, NULL);
        WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);

        //
        // Execute the specified routine.
        //

        (WorkItem->WorkerRoutine)(WorkItem->Parameter);
        if (KeGetCurrentIrql() != 0) {
            KeBugCheckEx(
                IRQL_NOT_LESS_OR_EQUAL,
                (ULONG)WorkItem->WorkerRoutine,
                (ULONG)KeGetCurrentIrql(),
                (ULONG)WorkItem->WorkerRoutine,
                (ULONG)WorkItem
                );
        }

    } while(TRUE);
}