Source code of Windows XP (NT5)
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.

430 lines
9.4 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. //
  77. // Create worker threads to handle normal and paging overflow reads.
  78. //
  79. InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
  80. for (i=0; i < 2; i++) {
  81. //
  82. // Initialize the FsRtl stack overflow work Queue objects.
  83. //
  84. KeInitializeQueue(&FsRtlWorkerQueues[i], 0);
  85. if (!NT_SUCCESS(PsCreateSystemThread(&Thread,
  86. THREAD_ALL_ACCESS,
  87. &ObjectAttributes,
  88. 0L,
  89. NULL,
  90. FsRtlWorkerThread,
  91. ULongToPtr( i )))) {
  92. return FALSE;
  93. }
  94. ZwClose( Thread );
  95. }
  96. //
  97. // Initialize the serial workitem so we can guarantee to post items
  98. // for paging files to the worker threads.
  99. //
  100. KeInitializeEvent( &StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE );
  101. return TRUE;
  102. }
  103. VOID
  104. FsRtlPostStackOverflow (
  105. IN PVOID Context,
  106. IN PKEVENT Event,
  107. IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine
  108. )
  109. /*++
  110. Routine Description:
  111. This routines posts a stack overflow item to the stack overflow
  112. thread and returns.
  113. Arguments:
  114. Context - Supplies the context to pass to the stack overflow
  115. call back routine. If the low order bit is set, then
  116. this overflow was a read to a paging file.
  117. Event - Supplies a pointer to an event to pass to the stack
  118. overflow call back routine.
  119. StackOverflowRoutine - Supplies the call back to use when
  120. processing the request in the overflow thread.
  121. Return Value:
  122. None.
  123. --*/
  124. {
  125. FsRtlpPostStackOverflow( Context, Event, StackOverflowRoutine, FALSE );
  126. return;
  127. }
  128. VOID
  129. FsRtlPostPagingFileStackOverflow (
  130. IN PVOID Context,
  131. IN PKEVENT Event,
  132. IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine
  133. )
  134. /*++
  135. Routine Description:
  136. This routines posts a stack overflow item to the stack overflow
  137. thread and returns.
  138. Arguments:
  139. Context - Supplies the context to pass to the stack overflow
  140. call back routine. If the low order bit is set, then
  141. this overflow was a read to a paging file.
  142. Event - Supplies a pointer to an event to pass to the stack
  143. overflow call back routine.
  144. StackOverflowRoutine - Supplies the call back to use when
  145. processing the request in the overflow thread.
  146. Return Value:
  147. None.
  148. --*/
  149. {
  150. FsRtlpPostStackOverflow( Context, Event, StackOverflowRoutine, TRUE );
  151. return;
  152. }
  153. VOID
  154. FsRtlpPostStackOverflow (
  155. IN PVOID Context,
  156. IN PKEVENT Event,
  157. IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine,
  158. IN BOOLEAN PagingFile
  159. )
  160. /*++
  161. Routine Description:
  162. This routines posts a stack overflow item to the stack overflow
  163. thread and returns.
  164. Arguments:
  165. Context - Supplies the context to pass to the stack overflow
  166. call back routine. If the low order bit is set, then
  167. this overflow was a read to a paging file.
  168. Event - Supplies a pointer to an event to pass to the stack
  169. overflow call back routine.
  170. StackOverflowRoutine - Supplies the call back to use when
  171. processing the request in the overflow thread.
  172. PagingFile - Indicates if the read is destined to a paging file.
  173. Return Value:
  174. None.
  175. --*/
  176. {
  177. PSTACK_OVERFLOW_ITEM StackOverflowItem;
  178. //
  179. // Allocate a stack overflow work item it will later be deallocated by
  180. // the stack overflow thread. Conserve stack by raising here.
  181. //
  182. StackOverflowItem = ExAllocatePoolWithTag( NonPagedPool,
  183. sizeof(STACK_OVERFLOW_ITEM),
  184. MODULE_POOL_TAG );
  185. //
  186. // If this fails, go to the fallback item for the paging file overflows.
  187. // We can't have a single fallback item for non-pagingfile IO since this
  188. // could lead to deadlocks if it waits on a thread that itself needs
  189. // the fallback item.
  190. //
  191. if (StackOverflowItem == NULL) {
  192. if (!PagingFile) {
  193. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  194. }
  195. KeWaitForSingleObject( &StackOverflowFallbackSerialEvent,
  196. Executive,
  197. KernelMode,
  198. FALSE,
  199. NULL );
  200. StackOverflowItem = &StackOverflowFallback;
  201. }
  202. //
  203. // Fill in the fields in the new item
  204. //
  205. StackOverflowItem->Context = Context;
  206. StackOverflowItem->Event = Event;
  207. StackOverflowItem->StackOverflowRoutine = StackOverflowRoutine;
  208. ExInitializeWorkItem( &StackOverflowItem->Item,
  209. &FsRtlStackOverflowRead,
  210. StackOverflowItem );
  211. //
  212. // Safely add it to the overflow queue
  213. //
  214. KeInsertQueue( &FsRtlWorkerQueues[PagingFile],
  215. &StackOverflowItem->Item.List );
  216. //
  217. // And return to our caller
  218. //
  219. return;
  220. }
  221. //
  222. // Local Support Routine
  223. //
  224. VOID
  225. FsRtlStackOverflowRead (
  226. IN PVOID Context
  227. )
  228. /*++
  229. Routine Description:
  230. This routine processes all of the stack overflow request posted by
  231. the various file systems
  232. Arguments:
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. PSTACK_OVERFLOW_ITEM StackOverflowItem;
  238. //
  239. // Since stack overflow reads are always recursive, set the
  240. // TopLevelIrp field appropriately so that recurive reads
  241. // from this point will not think they are top level.
  242. //
  243. PsGetCurrentThread()->TopLevelIrp = FSRTL_FSP_TOP_LEVEL_IRP;
  244. //
  245. // Get a pointer to the stack overflow item and then call
  246. // the callback routine to do the work
  247. //
  248. StackOverflowItem = (PSTACK_OVERFLOW_ITEM)Context;
  249. (StackOverflowItem->StackOverflowRoutine)(StackOverflowItem->Context,
  250. StackOverflowItem->Event);
  251. //
  252. // Deallocate the work item, or simply return the serial item.
  253. //
  254. if (StackOverflowItem == &StackOverflowFallback) {
  255. KeSetEvent( &StackOverflowFallbackSerialEvent, 0, FALSE );
  256. } else {
  257. ExFreePool( StackOverflowItem );
  258. }
  259. PsGetCurrentThread()->TopLevelIrp = (ULONG_PTR)NULL;
  260. }
  261. VOID
  262. FsRtlWorkerThread(
  263. IN PVOID StartContext
  264. )
  265. {
  266. PLIST_ENTRY Entry;
  267. PWORK_QUEUE_ITEM WorkItem;
  268. ULONG PagingFile = (ULONG)(ULONG_PTR)StartContext;
  269. //
  270. // Set our priority to low realtime, or +1 for PagingFile.
  271. //
  272. (VOID)KeSetPriorityThread( &PsGetCurrentThread()->Tcb,
  273. LOW_REALTIME_PRIORITY + PagingFile );
  274. //
  275. // Loop forever waiting for a work queue item, calling the processing
  276. // routine, and then waiting for another work queue item.
  277. //
  278. do {
  279. //
  280. // Wait until something is put in the queue.
  281. //
  282. // By specifying a wait mode of KernelMode, the thread's kernel stack is
  283. // NOT swappable
  284. //
  285. Entry = KeRemoveQueue(&FsRtlWorkerQueues[PagingFile], KernelMode, NULL);
  286. WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
  287. //
  288. // Execute the specified routine.
  289. //
  290. (WorkItem->WorkerRoutine)(WorkItem->Parameter);
  291. if (KeGetCurrentIrql() != 0) {
  292. KeBugCheckEx(
  293. IRQL_NOT_LESS_OR_EQUAL,
  294. (ULONG_PTR)WorkItem->WorkerRoutine,
  295. (ULONG_PTR)KeGetCurrentIrql(),
  296. (ULONG_PTR)WorkItem->WorkerRoutine,
  297. (ULONG_PTR)WorkItem
  298. );
  299. }
  300. } while(TRUE);
  301. }