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 25 typedef 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 34 KEVENT StackOverflowFallbackSerialEvent; 35 STACK_OVERFLOW_WORK_ITEM StackOverflowFallback; 36 KQUEUE FsRtlWorkerQueues[FSRTLP_MAX_QUEUES]; 37 38 /* PRIVATE FUNCTIONS *********************************************************/ 39 40 /* 41 * @implemented 42 */ 43 VOID 44 NTAPI 45 FsRtlStackOverflowRead(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, 'FSrs'); 65 } 66 67 /* Reset top level */ 68 IoSetTopLevelIrp(NULL); 69 } 70 71 /* 72 * @implemented 73 */ 74 VOID 75 NTAPI 76 FsRtlpPostStackOverflow(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), 'FSrs'); 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 */ 111 VOID 112 NTAPI 113 FsRtlWorkerThread(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 */ 147 INIT_FUNCTION 148 NTSTATUS 149 NTAPI 150 FsRtlInitializeWorkerThread(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 *--*/ 204 VOID 205 NTAPI 206 FsRtlPostPagingFileStackOverflow(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 *--*/ 230 VOID 231 NTAPI 232 FsRtlPostStackOverflow(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 */ 240