reactos/ntoskrnl/fsrtl/stackovf.c
Pierre Schweitzer 7eca874824
[NTOSKRNL] Fix FsRtlStackOverflow work item free.
Oneliner of the day... This typo just prevented the
whole feature to work properly. Because any allocated
work item would miserably fail to be freed.

This will obviously help real world FSD relying on
StackOverflow worker from FsRtl to work better!

CORE-14611
2018-05-10 10:49:17 +02:00

239 lines
6.4 KiB
C

/*
* 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
*/
VOID
NTAPI
FsRtlStackOverflowRead(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, 'FSrs');
}
/* Reset top level */
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;
/* Try to allocate a work item */
WorkItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(STACK_OVERFLOW_WORK_ITEM), 'FSrs');
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
*/
VOID
NTAPI
FsRtlWorkerThread(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
*/
NTSTATUS
NTAPI
INIT_FUNCTION
FsRtlInitializeWorkerThread(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.
*
*--*/
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);
}
/* EOF */