Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

433 lines
9.9 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. StackOvf.c
  5. Abstract:
  6. The file lock package provides a worker thread to handle
  7. stack overflow conditions in the file systems. When the
  8. file system detects that it is near the end of its stack
  9. during a paging I/O read request it will post the request
  10. to this extra thread.
  11. Author:
  12. Gary Kimura [GaryKi] 24-Nov-1992
  13. Revision History:
  14. --*/
  15. #include "FsRtlP.h"
  16. //
  17. // Queue object that is used to hold work queue entries and synchronize
  18. // worker thread activity.
  19. //
  20. KQUEUE FsRtlWorkerQueues[2];
  21. //
  22. // Define a tag for general pool allocations from this module
  23. //
  24. #undef MODULE_POOL_TAG
  25. #define MODULE_POOL_TAG ('srSF')
  26. //
  27. // Local Support Routine
  28. //
  29. VOID
  30. FsRtlStackOverflowRead (
  31. IN PVOID Context
  32. );
  33. VOID
  34. FsRtlpPostStackOverflow (
  35. IN PVOID Context,
  36. IN PKEVENT Event,
  37. IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine,
  38. IN BOOLEAN PagingFile
  39. );
  40. //
  41. // Procedure prototype for the worker thread.
  42. //
  43. VOID
  44. FsRtlWorkerThread(
  45. IN PVOID StartContext
  46. );
  47. //
  48. // The following type is used to store an enqueue work item
  49. //
  50. typedef struct _STACK_OVERFLOW_ITEM {
  51. WORK_QUEUE_ITEM Item;
  52. //
  53. // This is the call back routine
  54. //
  55. PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine;
  56. //
  57. // Here are the parameters for the call back routine
  58. //
  59. PVOID Context;
  60. PKEVENT Event;
  61. } STACK_OVERFLOW_ITEM;
  62. typedef STACK_OVERFLOW_ITEM *PSTACK_OVERFLOW_ITEM;
  63. KEVENT StackOverflowFallbackSerialEvent;
  64. STACK_OVERFLOW_ITEM StackOverflowFallback;
  65. #ifdef ALLOC_PRAGMA
  66. #pragma alloc_text(INIT, FsRtlInitializeWorkerThread)
  67. #endif
  68. NTSTATUS
  69. FsRtlInitializeWorkerThread (
  70. VOID
  71. )
  72. {
  73. OBJECT_ATTRIBUTES ObjectAttributes;
  74. HANDLE Thread;
  75. ULONG i;
  76. NTSTATUS Status = STATUS_SUCCESS;
  77. //
  78. // Create worker threads to handle normal and paging overflow reads.
  79. //
  80. InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
  81. for (i=0; i < 2; i++) {
  82. //
  83. // Initialize the FsRtl stack overflow work Queue objects.
  84. //
  85. KeInitializeQueue(&FsRtlWorkerQueues[i], 0);
  86. Status = PsCreateSystemThread( &Thread,
  87. THREAD_ALL_ACCESS,
  88. &ObjectAttributes,
  89. 0L,
  90. NULL,
  91. FsRtlWorkerThread,
  92. ULongToPtr( i ));
  93. if (!NT_SUCCESS( Status )) {
  94. return Status;
  95. }
  96. ZwClose( Thread );
  97. }
  98. //
  99. // Initialize the serial workitem so we can guarantee to post items
  100. // for paging files to the worker threads.
  101. //
  102. KeInitializeEvent( &StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE );
  103. return Status;
  104. }
  105. VOID
  106. FsRtlPostStackOverflow (
  107. IN PVOID Context,
  108. IN PKEVENT Event,
  109. IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine
  110. )
  111. /*++
  112. Routine Description:
  113. This routines posts a stack overflow item to the stack overflow
  114. thread and returns.
  115. Arguments:
  116. Context - Supplies the context to pass to the stack overflow
  117. call back routine. If the low order bit is set, then
  118. this overflow was a read to a paging file.
  119. Event - Supplies a pointer to an event to pass to the stack
  120. overflow call back routine.
  121. StackOverflowRoutine - Supplies the call back to use when
  122. processing the request in the overflow thread.
  123. Return Value:
  124. None.
  125. --*/
  126. {
  127. FsRtlpPostStackOverflow( Context, Event, StackOverflowRoutine, FALSE );
  128. return;
  129. }
  130. VOID
  131. FsRtlPostPagingFileStackOverflow (
  132. IN PVOID Context,
  133. IN PKEVENT Event,
  134. IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine
  135. )
  136. /*++
  137. Routine Description:
  138. This routines posts a stack overflow item to the stack overflow
  139. thread and returns.
  140. Arguments:
  141. Context - Supplies the context to pass to the stack overflow
  142. call back routine. If the low order bit is set, then
  143. this overflow was a read to a paging file.
  144. Event - Supplies a pointer to an event to pass to the stack
  145. overflow call back routine.
  146. StackOverflowRoutine - Supplies the call back to use when
  147. processing the request in the overflow thread.
  148. Return Value:
  149. None.
  150. --*/
  151. {
  152. FsRtlpPostStackOverflow( Context, Event, StackOverflowRoutine, TRUE );
  153. return;
  154. }
  155. VOID
  156. FsRtlpPostStackOverflow (
  157. IN PVOID Context,
  158. IN PKEVENT Event,
  159. IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine,
  160. IN BOOLEAN PagingFile
  161. )
  162. /*++
  163. Routine Description:
  164. This routines posts a stack overflow item to the stack overflow
  165. thread and returns.
  166. Arguments:
  167. Context - Supplies the context to pass to the stack overflow
  168. call back routine. If the low order bit is set, then
  169. this overflow was a read to a paging file.
  170. Event - Supplies a pointer to an event to pass to the stack
  171. overflow call back routine.
  172. StackOverflowRoutine - Supplies the call back to use when
  173. processing the request in the overflow thread.
  174. PagingFile - Indicates if the read is destined to a paging file.
  175. Return Value:
  176. None.
  177. --*/
  178. {
  179. PSTACK_OVERFLOW_ITEM StackOverflowItem;
  180. //
  181. // Allocate a stack overflow work item it will later be deallocated by
  182. // the stack overflow thread. Conserve stack by raising here.
  183. //
  184. StackOverflowItem = ExAllocatePoolWithTag( NonPagedPool,
  185. sizeof(STACK_OVERFLOW_ITEM),
  186. MODULE_POOL_TAG );
  187. //
  188. // If this fails, go to the fallback item for the paging file overflows.
  189. // We can't have a single fallback item for non-pagingfile IO since this
  190. // could lead to deadlocks if it waits on a thread that itself needs
  191. // the fallback item.
  192. //
  193. if (StackOverflowItem == NULL) {
  194. if (!PagingFile) {
  195. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  196. }
  197. KeWaitForSingleObject( &StackOverflowFallbackSerialEvent,
  198. Executive,
  199. KernelMode,
  200. FALSE,
  201. NULL );
  202. StackOverflowItem = &StackOverflowFallback;
  203. }
  204. //
  205. // Fill in the fields in the new item
  206. //
  207. StackOverflowItem->Context = Context;
  208. StackOverflowItem->Event = Event;
  209. StackOverflowItem->StackOverflowRoutine = StackOverflowRoutine;
  210. ExInitializeWorkItem( &StackOverflowItem->Item,
  211. &FsRtlStackOverflowRead,
  212. StackOverflowItem );
  213. //
  214. // Safely add it to the overflow queue
  215. //
  216. KeInsertQueue( &FsRtlWorkerQueues[PagingFile],
  217. &StackOverflowItem->Item.List );
  218. //
  219. // And return to our caller
  220. //
  221. return;
  222. }
  223. //
  224. // Local Support Routine
  225. //
  226. VOID
  227. FsRtlStackOverflowRead (
  228. IN PVOID Context
  229. )
  230. /*++
  231. Routine Description:
  232. This routine processes all of the stack overflow request posted by
  233. the various file systems
  234. Arguments:
  235. Return Value:
  236. None.
  237. --*/
  238. {
  239. PSTACK_OVERFLOW_ITEM StackOverflowItem;
  240. //
  241. // Since stack overflow reads are always recursive, set the
  242. // TopLevelIrp field appropriately so that recurive reads
  243. // from this point will not think they are top level.
  244. //
  245. PsGetCurrentThread()->TopLevelIrp = FSRTL_FSP_TOP_LEVEL_IRP;
  246. //
  247. // Get a pointer to the stack overflow item and then call
  248. // the callback routine to do the work
  249. //
  250. StackOverflowItem = (PSTACK_OVERFLOW_ITEM)Context;
  251. (StackOverflowItem->StackOverflowRoutine)(StackOverflowItem->Context,
  252. StackOverflowItem->Event);
  253. //
  254. // Deallocate the work item, or simply return the serial item.
  255. //
  256. if (StackOverflowItem == &StackOverflowFallback) {
  257. KeSetEvent( &StackOverflowFallbackSerialEvent, 0, FALSE );
  258. } else {
  259. ExFreePool( StackOverflowItem );
  260. }
  261. PsGetCurrentThread()->TopLevelIrp = (ULONG_PTR)NULL;
  262. }
  263. VOID
  264. FsRtlWorkerThread(
  265. IN PVOID StartContext
  266. )
  267. {
  268. PLIST_ENTRY Entry;
  269. PWORK_QUEUE_ITEM WorkItem;
  270. ULONG PagingFile = (ULONG)(ULONG_PTR)StartContext;
  271. //
  272. // Set our priority to low realtime, or +1 for PagingFile.
  273. //
  274. (VOID)KeSetPriorityThread( &PsGetCurrentThread()->Tcb,
  275. LOW_REALTIME_PRIORITY + PagingFile );
  276. //
  277. // Loop forever waiting for a work queue item, calling the processing
  278. // routine, and then waiting for another work queue item.
  279. //
  280. do {
  281. //
  282. // Wait until something is put in the queue.
  283. //
  284. // By specifying a wait mode of KernelMode, the thread's kernel stack is
  285. // NOT swappable
  286. //
  287. Entry = KeRemoveQueue(&FsRtlWorkerQueues[PagingFile], KernelMode, NULL);
  288. WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
  289. //
  290. // Execute the specified routine.
  291. //
  292. (WorkItem->WorkerRoutine)(WorkItem->Parameter);
  293. if (KeGetCurrentIrql() != 0) {
  294. KeBugCheckEx(
  295. IRQL_NOT_LESS_OR_EQUAL,
  296. (ULONG_PTR)WorkItem->WorkerRoutine,
  297. (ULONG_PTR)KeGetCurrentIrql(),
  298. (ULONG_PTR)WorkItem->WorkerRoutine,
  299. (ULONG_PTR)WorkItem
  300. );
  301. }
  302. } while(TRUE);
  303. }