Sync with trunk r63502.
[reactos.git] / ntoskrnl / fsrtl / stackovf.c
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 QueueId = (ULONG)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 NTSTATUS
148 NTAPI
149 INIT_FUNCTION
150 FsRtlInitializeWorkerThread(VOID)
151 {
152 ULONG 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 */