Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240/* * 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) */
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* GLOBALS *******************************************************************/
/* We have one queue for paging files, one queue for normal files * 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];
/* PRIVATE FUNCTIONS *********************************************************/
/* * @implemented */VOIDNTAPIFsRtlStackOverflowRead(IN PVOID Context){ PSTACK_OVERFLOW_WORK_ITEM WorkItem;
WorkItem = (PSTACK_OVERFLOW_WORK_ITEM)Context;
/* Put us as top IRP for current thread */ IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); /* And call FsRtlSORoutine */ WorkItem->Routine(WorkItem->Context, WorkItem->Event);
/* If we were using fallback workitem, don't free it, just reset event */ if (WorkItem == &StackOverflowFallback) { KeSetEvent(&StackOverflowFallbackSerialEvent, 0, FALSE); } /* Otherwise, free the work item */ else { ExFreePoolWithTag(WorkItem, 'srSF'); }
/* Reset top level */ IoSetTopLevelIrp(NULL);}
/* * @implemented */VOIDNTAPIFsRtlpPostStackOverflow(IN PVOID Context, IN PKEVENT Event, IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine, IN BOOLEAN IsPaging){ PSTACK_OVERFLOW_WORK_ITEM WorkItem;
/* Try to allocate a work item */ WorkItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(STACK_OVERFLOW_WORK_ITEM), 'srSF'); if (WorkItem == NULL) { /* If we failed, and we are not a paging file, just raise an error */ if (!IsPaging) { RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); }
/* Otherwise, wait for fallback workitem to be available and use it */ KeWaitForSingleObject(&StackOverflowFallbackSerialEvent, Executive, KernelMode, FALSE, NULL); WorkItem = &StackOverflowFallback; }
/* Initialize work item */ WorkItem->Context = Context; WorkItem->Event = Event; WorkItem->Routine = StackOverflowRoutine; ExInitializeWorkItem(&WorkItem->WorkItem, FsRtlStackOverflowRead, WorkItem);
/* And queue it in the appropriate queue (paging or not?) */ KeInsertQueue(&FsRtlWorkerQueues[IsPaging], &WorkItem->WorkItem.List);}
/* * @implemented */VOIDNTAPIFsRtlWorkerThread(IN PVOID StartContext){ KIRQL Irql; PLIST_ENTRY Entry; PWORK_QUEUE_ITEM WorkItem; ULONG_PTR QueueId = (ULONG_PTR)StartContext;
/* Set our priority according to the queue we're dealing with */ KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + QueueId);
/* Loop for events */ for (;;) { /* Look for next event */ Entry = KeRemoveQueue(&FsRtlWorkerQueues[QueueId], KernelMode, NULL); WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
/* Call its routine (here: FsRtlStackOverflowRead) */ WorkItem->WorkerRoutine(WorkItem->Parameter);
/* Check we're still at passive level or bugcheck */ 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")NTSTATUSNTAPIFsRtlInitializeWorkerThread(VOID){ ULONG_PTR i; NTSTATUS Status; HANDLE ThreadHandle; OBJECT_ATTRIBUTES ObjectAttributes;
/* Initialize each queue we have */ for (i = 0; i < FSRTLP_MAX_QUEUES; ++i) { InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
/* Initialize the queue and its associated thread and pass it the queue ID */ KeInitializeQueue(&FsRtlWorkerQueues[i], 0); Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, 0, 0, FsRtlWorkerThread, (PVOID)i); if (!NT_SUCCESS(Status)) { return Status; }
/* Don't leak handle */ ZwClose(ThreadHandle); }
/* Also initialize our fallback event, set it to ensure it's already usable */ KeInitializeEvent(&StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE);
return Status;}
/* PUBLIC FUNCTIONS **********************************************************/
/*++ * @name FsRtlPostPagingFileStackOverflow * @implemented NT 5.2 * * The FsRtlPostPagingFileStackOverflow routine * * @param Context * * @param Event * * @param StackOverflowRoutine * * @return * * @remarks None. * *--*/VOIDNTAPIFsRtlPostPagingFileStackOverflow(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. * *--*/VOIDNTAPIFsRtlPostStackOverflow(IN PVOID Context, IN PKEVENT Event, IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine){ FsRtlpPostStackOverflow(Context, Event, StackOverflowRoutine, FALSE);}
/* EOF */