|
|
/*++
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];
//
// Define a tag for general pool allocations from this module
//
#undef MODULE_POOL_TAG
#define MODULE_POOL_TAG ('srSF')
//
// 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;
KEVENT StackOverflowFallbackSerialEvent; STACK_OVERFLOW_ITEM StackOverflowFallback;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, FsRtlInitializeWorkerThread)
#endif
NTSTATUS FsRtlInitializeWorkerThread ( VOID ) { OBJECT_ATTRIBUTES ObjectAttributes; HANDLE Thread; ULONG i; NTSTATUS Status = STATUS_SUCCESS;
//
// 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);
Status = PsCreateSystemThread( &Thread, THREAD_ALL_ACCESS, &ObjectAttributes, 0L, NULL, FsRtlWorkerThread, ULongToPtr( i )); if (!NT_SUCCESS( Status )) {
return Status; }
ZwClose( Thread ); }
//
// Initialize the serial workitem so we can guarantee to post items
// for paging files to the worker threads.
//
KeInitializeEvent( &StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE );
return Status; }
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. Conserve stack by raising here.
//
StackOverflowItem = ExAllocatePoolWithTag( NonPagedPool, sizeof(STACK_OVERFLOW_ITEM), MODULE_POOL_TAG );
//
// If this fails, go to the fallback item for the paging file overflows.
// We can't have a single fallback item for non-pagingfile IO since this
// could lead to deadlocks if it waits on a thread that itself needs
// the fallback item.
//
if (StackOverflowItem == NULL) { if (!PagingFile) { ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); }
KeWaitForSingleObject( &StackOverflowFallbackSerialEvent, Executive, KernelMode, FALSE, NULL );
StackOverflowItem = &StackOverflowFallback; } //
// 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, or simply return the serial item.
//
if (StackOverflowItem == &StackOverflowFallback) {
KeSetEvent( &StackOverflowFallbackSerialEvent, 0, FALSE ); } else { ExFreePool( StackOverflowItem ); }
PsGetCurrentThread()->TopLevelIrp = (ULONG_PTR)NULL; }
VOID FsRtlWorkerThread( IN PVOID StartContext )
{ PLIST_ENTRY Entry; PWORK_QUEUE_ITEM WorkItem; ULONG PagingFile = (ULONG)(ULONG_PTR)StartContext;
//
// Set our priority to low realtime, or +1 for PagingFile.
//
(VOID)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_PTR)WorkItem->WorkerRoutine, (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)WorkItem->WorkerRoutine, (ULONG_PTR)WorkItem ); }
} while(TRUE); }
|