Reactos
at master 239 lines 6.5 kB view raw
1/* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/fsrtl/stackovf.c 5 * PURPOSE: Provides Stack Overflow support for File System Drivers 6 * PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org) 7 */ 8 9/* INCLUDES ******************************************************************/ 10 11#include <ntoskrnl.h> 12#define NDEBUG 13#include <debug.h> 14 15/* GLOBALS *******************************************************************/ 16 17/* We have one queue for paging files, one queue for normal files 18 * Queue 0 is for non-paging files 19 * Queue 1 is for paging files 20 * Don't add new/change current queues unless you know what you do 21 * Most of the code relies on the fact that we have two queues in that order 22 */ 23#define FSRTLP_MAX_QUEUES 2 24 25typedef struct _STACK_OVERFLOW_WORK_ITEM 26{ 27 28 WORK_QUEUE_ITEM WorkItem; 29 PFSRTL_STACK_OVERFLOW_ROUTINE Routine; 30 PVOID Context; 31 PKEVENT Event; 32} STACK_OVERFLOW_WORK_ITEM, *PSTACK_OVERFLOW_WORK_ITEM; 33 34KEVENT StackOverflowFallbackSerialEvent; 35STACK_OVERFLOW_WORK_ITEM StackOverflowFallback; 36KQUEUE FsRtlWorkerQueues[FSRTLP_MAX_QUEUES]; 37 38/* PRIVATE FUNCTIONS *********************************************************/ 39 40/* 41 * @implemented 42 */ 43VOID 44NTAPI 45FsRtlStackOverflowRead(IN PVOID Context) 46{ 47 PSTACK_OVERFLOW_WORK_ITEM WorkItem; 48 49 WorkItem = (PSTACK_OVERFLOW_WORK_ITEM)Context; 50 51 /* Put us as top IRP for current thread */ 52 IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); 53 /* And call FsRtlSORoutine */ 54 WorkItem->Routine(WorkItem->Context, WorkItem->Event); 55 56 /* If we were using fallback workitem, don't free it, just reset event */ 57 if (WorkItem == &StackOverflowFallback) 58 { 59 KeSetEvent(&StackOverflowFallbackSerialEvent, 0, FALSE); 60 } 61 /* Otherwise, free the work item */ 62 else 63 { 64 ExFreePoolWithTag(WorkItem, 'srSF'); 65 } 66 67 /* Reset top level */ 68 IoSetTopLevelIrp(NULL); 69} 70 71/* 72 * @implemented 73 */ 74VOID 75NTAPI 76FsRtlpPostStackOverflow(IN PVOID Context, 77 IN PKEVENT Event, 78 IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine, 79 IN BOOLEAN IsPaging) 80{ 81 PSTACK_OVERFLOW_WORK_ITEM WorkItem; 82 83 /* Try to allocate a work item */ 84 WorkItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(STACK_OVERFLOW_WORK_ITEM), 'srSF'); 85 if (WorkItem == NULL) 86 { 87 /* If we failed, and we are not a paging file, just raise an error */ 88 if (!IsPaging) 89 { 90 RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 91 } 92 93 /* Otherwise, wait for fallback workitem to be available and use it */ 94 KeWaitForSingleObject(&StackOverflowFallbackSerialEvent, Executive, KernelMode, FALSE, NULL); 95 WorkItem = &StackOverflowFallback; 96 } 97 98 /* Initialize work item */ 99 WorkItem->Context = Context; 100 WorkItem->Event = Event; 101 WorkItem->Routine = StackOverflowRoutine; 102 ExInitializeWorkItem(&WorkItem->WorkItem, FsRtlStackOverflowRead, WorkItem); 103 104 /* And queue it in the appropriate queue (paging or not?) */ 105 KeInsertQueue(&FsRtlWorkerQueues[IsPaging], &WorkItem->WorkItem.List); 106} 107 108/* 109 * @implemented 110 */ 111VOID 112NTAPI 113FsRtlWorkerThread(IN PVOID StartContext) 114{ 115 KIRQL Irql; 116 PLIST_ENTRY Entry; 117 PWORK_QUEUE_ITEM WorkItem; 118 ULONG_PTR QueueId = (ULONG_PTR)StartContext; 119 120 /* Set our priority according to the queue we're dealing with */ 121 KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + QueueId); 122 123 /* Loop for events */ 124 for (;;) 125 { 126 /* Look for next event */ 127 Entry = KeRemoveQueue(&FsRtlWorkerQueues[QueueId], KernelMode, NULL); 128 WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List); 129 130 /* Call its routine (here: FsRtlStackOverflowRead) */ 131 WorkItem->WorkerRoutine(WorkItem->Parameter); 132 133 /* Check we're still at passive level or bugcheck */ 134 Irql = KeGetCurrentIrql(); 135 if (Irql != PASSIVE_LEVEL) 136 { 137 KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL, (ULONG_PTR)WorkItem->WorkerRoutine, 138 (ULONG_PTR)Irql, (ULONG_PTR)WorkItem->WorkerRoutine, 139 (ULONG_PTR)WorkItem); 140 } 141 } 142} 143 144/* 145 * @implemented 146 */ 147CODE_SEG("INIT") 148NTSTATUS 149NTAPI 150FsRtlInitializeWorkerThread(VOID) 151{ 152 ULONG_PTR i; 153 NTSTATUS Status; 154 HANDLE ThreadHandle; 155 OBJECT_ATTRIBUTES ObjectAttributes; 156 157 /* Initialize each queue we have */ 158 for (i = 0; i < FSRTLP_MAX_QUEUES; ++i) 159 { 160 InitializeObjectAttributes(&ObjectAttributes, 161 NULL, 162 0, 163 NULL, 164 NULL); 165 166 /* Initialize the queue and its associated thread and pass it the queue ID */ 167 KeInitializeQueue(&FsRtlWorkerQueues[i], 0); 168 Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, 169 0, 0, FsRtlWorkerThread, (PVOID)i); 170 if (!NT_SUCCESS(Status)) 171 { 172 return Status; 173 } 174 175 /* Don't leak handle */ 176 ZwClose(ThreadHandle); 177 } 178 179 /* Also initialize our fallback event, set it to ensure it's already usable */ 180 KeInitializeEvent(&StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE); 181 182 return Status; 183} 184 185/* PUBLIC FUNCTIONS **********************************************************/ 186 187/*++ 188 * @name FsRtlPostPagingFileStackOverflow 189 * @implemented NT 5.2 190 * 191 * The FsRtlPostPagingFileStackOverflow routine 192 * 193 * @param Context 194 * 195 * @param Event 196 * 197 * @param StackOverflowRoutine 198 * 199 * @return 200 * 201 * @remarks None. 202 * 203 *--*/ 204VOID 205NTAPI 206FsRtlPostPagingFileStackOverflow(IN PVOID Context, 207 IN PKEVENT Event, 208 IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine) 209{ 210 FsRtlpPostStackOverflow(Context, Event, StackOverflowRoutine, TRUE); 211} 212 213/*++ 214 * @name FsRtlPostStackOverflow 215 * @implemented NT 5.2 216 * 217 * The FsRtlPostStackOverflow routine 218 * 219 * @param Context 220 * 221 * @param Event 222 * 223 * @param StackOverflowRoutine 224 * 225 * @return 226 * 227 * @remarks None. 228 * 229 *--*/ 230VOID 231NTAPI 232FsRtlPostStackOverflow(IN PVOID Context, 233 IN PKEVENT Event, 234 IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine) 235{ 236 FsRtlpPostStackOverflow(Context, Event, StackOverflowRoutine, FALSE); 237} 238 239/* EOF */