* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/fsrtl/stackovf.c
* PURPOSE: Provides Stack Overflow support for File System Drivers
* PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org)
*/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
* Queue 0 is for non-paging files
* Queue 1 is for paging files
* Don't add new/change current queues unless you know what you do
* Most of the code relies on the fact that we have two queues in that order
*/
#define FSRTLP_MAX_QUEUES 2
typedef struct _STACK_OVERFLOW_WORK_ITEM
{
WORK_QUEUE_ITEM WorkItem;
PFSRTL_STACK_OVERFLOW_ROUTINE Routine;
PVOID Context;
PKEVENT Event;
} STACK_OVERFLOW_WORK_ITEM, *PSTACK_OVERFLOW_WORK_ITEM;
KEVENT StackOverflowFallbackSerialEvent;
STACK_OVERFLOW_WORK_ITEM StackOverflowFallback;
KQUEUE FsRtlWorkerQueues[FSRTLP_MAX_QUEUES];
* @implemented
*/
VOID
NTAPI
FsRtlStackOverflowRead(IN PVOID Context)
{
PSTACK_OVERFLOW_WORK_ITEM WorkItem;
WorkItem = (PSTACK_OVERFLOW_WORK_ITEM)Context;
IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
WorkItem->Routine(WorkItem->Context, WorkItem->Event);
if (WorkItem == &StackOverflowFallback)
{
KeSetEvent(&StackOverflowFallbackSerialEvent, 0, FALSE);
}
else
{
ExFreePoolWithTag(WorkItem, 'srSF');
}
IoSetTopLevelIrp(NULL);
}
* @implemented
*/
VOID
NTAPI
FsRtlpPostStackOverflow(IN PVOID Context,
IN PKEVENT Event,
IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine,
IN BOOLEAN IsPaging)
{
PSTACK_OVERFLOW_WORK_ITEM WorkItem;
WorkItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(STACK_OVERFLOW_WORK_ITEM), 'srSF');
if (WorkItem == NULL)
{
if (!IsPaging)
{
RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
}
KeWaitForSingleObject(&StackOverflowFallbackSerialEvent, Executive, KernelMode, FALSE, NULL);
WorkItem = &StackOverflowFallback;
}
WorkItem->Context = Context;
WorkItem->Event = Event;
WorkItem->Routine = StackOverflowRoutine;
ExInitializeWorkItem(&WorkItem->WorkItem, FsRtlStackOverflowRead, WorkItem);
KeInsertQueue(&FsRtlWorkerQueues[IsPaging], &WorkItem->WorkItem.List);
}
* @implemented
*/
VOID
NTAPI
FsRtlWorkerThread(IN PVOID StartContext)
{
KIRQL Irql;
PLIST_ENTRY Entry;
PWORK_QUEUE_ITEM WorkItem;
ULONG_PTR QueueId = (ULONG_PTR)StartContext;
KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + QueueId);
for (;;)
{
Entry = KeRemoveQueue(&FsRtlWorkerQueues[QueueId], KernelMode, NULL);
WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
WorkItem->WorkerRoutine(WorkItem->Parameter);
Irql = KeGetCurrentIrql();
if (Irql != PASSIVE_LEVEL)
{
KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL, (ULONG_PTR)WorkItem->WorkerRoutine,
(ULONG_PTR)Irql, (ULONG_PTR)WorkItem->WorkerRoutine,
(ULONG_PTR)WorkItem);
}
}
}
* @implemented
*/
CODE_SEG("INIT")
NTSTATUS
NTAPI
FsRtlInitializeWorkerThread(VOID)
{
ULONG_PTR i;
NTSTATUS Status;
HANDLE ThreadHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
for (i = 0; i < FSRTLP_MAX_QUEUES; ++i)
{
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
NULL);
KeInitializeQueue(&FsRtlWorkerQueues[i], 0);
Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes,
0, 0, FsRtlWorkerThread, (PVOID)i);
if (!NT_SUCCESS(Status))
{
return Status;
}
ZwClose(ThreadHandle);
}
KeInitializeEvent(&StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE);
return Status;
}
* @name FsRtlPostPagingFileStackOverflow
* @implemented NT 5.2
*
* The FsRtlPostPagingFileStackOverflow routine
*
* @param Context
*
* @param Event
*
* @param StackOverflowRoutine
*
* @return
*
* @remarks None.
*
*--*/
VOID
NTAPI
FsRtlPostPagingFileStackOverflow(IN PVOID Context,
IN PKEVENT Event,
IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine)
{
FsRtlpPostStackOverflow(Context, Event, StackOverflowRoutine, TRUE);
}
* @name FsRtlPostStackOverflow
* @implemented NT 5.2
*
* The FsRtlPostStackOverflow routine
*
* @param Context
*
* @param Event
*
* @param StackOverflowRoutine
*
* @return
*
* @remarks None.
*
*--*/
VOID
NTAPI
FsRtlPostStackOverflow(IN PVOID Context,
IN PKEVENT Event,
IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine)
{
FsRtlpPostStackOverflow(Context, Event, StackOverflowRoutine, FALSE);
}