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.

415 lines
8.7 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. WorkQue.c
  5. Abstract:
  6. This module implements the Work queue routines for the Udfs File
  7. system.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Dan Lovinger [DanLo] 23-Sep-1996
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "UdfProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (UDFS_BUG_CHECK_WORKQUE)
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (UDFS_DEBUG_LEVEL_WORKQUE)
  23. //
  24. // The following constant is the maximum number of ExWorkerThreads that we
  25. // will allow to be servicing a particular target device at any one time.
  26. //
  27. #define FSP_PER_DEVICE_THRESHOLD (2)
  28. //
  29. // Local support routines
  30. //
  31. VOID
  32. UdfAddToWorkque (
  33. IN PIRP_CONTEXT IrpContext,
  34. IN PIRP Irp
  35. );
  36. #ifdef ALLOC_PRAGMA
  37. #pragma alloc_text(PAGE, UdfFsdPostRequest)
  38. #pragma alloc_text(PAGE, UdfOplockComplete)
  39. #pragma alloc_text(PAGE, UdfPrePostIrp)
  40. #endif
  41. NTSTATUS
  42. UdfFsdPostRequest (
  43. IN PIRP_CONTEXT IrpContext,
  44. IN PIRP Irp
  45. )
  46. /*++
  47. Routine Description:
  48. This routine enqueues the request packet specified by IrpContext to the
  49. work queue associated with the FileSystemDeviceObject. This is a FSD
  50. routine.
  51. Arguments:
  52. IrpContext - Pointer to the IrpContext to be queued to the Fsp.
  53. Irp - I/O Request Packet.
  54. Return Value:
  55. STATUS_PENDING
  56. --*/
  57. {
  58. PAGED_CODE();
  59. ASSERT_IRP_CONTEXT( IrpContext );
  60. ASSERT_IRP( Irp );
  61. //
  62. // Posting is a three step operation. First lock down any buffers
  63. // in the Irp. Next cleanup the IrpContext for the post and finally
  64. // add this to a workque.
  65. //
  66. UdfPrePostIrp( IrpContext, Irp );
  67. UdfAddToWorkque( IrpContext, Irp );
  68. //
  69. // And return to our caller
  70. //
  71. return STATUS_PENDING;
  72. }
  73. VOID
  74. UdfPrePostIrp (
  75. IN PIRP_CONTEXT IrpContext,
  76. IN PIRP Irp
  77. )
  78. /*++
  79. Routine Description:
  80. This routine performs any neccessary work before STATUS_PENDING is
  81. returned with the Fsd thread. This routine is called within the
  82. filesystem and by the oplock package.
  83. Arguments:
  84. Context - Pointer to the IrpContext to be queued to the Fsp
  85. Irp - I/O Request Packet.
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  91. BOOLEAN RemovedFcb;
  92. PAGED_CODE();
  93. ASSERT_IRP_CONTEXT( IrpContext );
  94. ASSERT_IRP( Irp );
  95. //
  96. // Case on the type of the operation.
  97. //
  98. switch (IrpContext->MajorFunction) {
  99. case IRP_MJ_CREATE :
  100. //
  101. // If called from the oplock package then there is an
  102. // Fcb to possibly teardown. We will call the teardown
  103. // routine and release the Fcb if still present. The cleanup
  104. // code in create will know not to release this Fcb because
  105. // we will clear the pointer.
  106. //
  107. if ((IrpContext->TeardownFcb != NULL) &&
  108. *(IrpContext->TeardownFcb) != NULL) {
  109. UdfTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), FALSE, &RemovedFcb );
  110. if (!RemovedFcb) {
  111. UdfReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
  112. }
  113. *(IrpContext->TeardownFcb) = NULL;
  114. IrpContext->TeardownFcb = NULL;
  115. }
  116. break;
  117. //
  118. // We need to lock the user's buffer, unless this is an MDL-read,
  119. // in which case there is no user buffer.
  120. //
  121. case IRP_MJ_READ :
  122. if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
  123. UdfLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length, IoWriteAccess );
  124. }
  125. break;
  126. case IRP_MJ_WRITE :
  127. UdfLockUserBuffer( IrpContext, IrpSp->Parameters.Write.Length, IoReadAccess );
  128. break;
  129. //
  130. // We also need to check whether this is a query file operation.
  131. //
  132. case IRP_MJ_DIRECTORY_CONTROL :
  133. if (IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
  134. UdfLockUserBuffer( IrpContext, IrpSp->Parameters.QueryDirectory.Length, IoWriteAccess );
  135. }
  136. break;
  137. }
  138. //
  139. // Cleanup the IrpContext for the post.
  140. //
  141. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
  142. UdfCleanupIrpContext( IrpContext, TRUE );
  143. //
  144. // Mark the Irp to show that we've already returned pending to the user.
  145. //
  146. IoMarkIrpPending( Irp );
  147. return;
  148. }
  149. VOID
  150. UdfOplockComplete (
  151. IN PIRP_CONTEXT IrpContext,
  152. IN PIRP Irp
  153. )
  154. /*++
  155. Routine Description:
  156. This routine is called by the oplock package when an oplock break has
  157. completed, allowing an Irp to resume execution. If the status in
  158. the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
  159. Otherwise we complete the Irp with the status in the Irp.
  160. If we are completing due to an error then check if there is any
  161. cleanup to do.
  162. Arguments:
  163. Irp - I/O Request Packet.
  164. Return Value:
  165. None.
  166. --*/
  167. {
  168. BOOLEAN RemovedFcb;
  169. PAGED_CODE();
  170. //
  171. // Check on the return value in the Irp. If success then we
  172. // are to post this request.
  173. //
  174. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  175. //
  176. // Check if there is any cleanup work to do.
  177. //
  178. switch (IrpContext->MajorFunction) {
  179. case IRP_MJ_CREATE :
  180. //
  181. // If called from the oplock package then there is an
  182. // Fcb to possibly teardown. We will call the teardown
  183. // routine and release the Fcb if still present. The cleanup
  184. // code in create will know not to release this Fcb because
  185. // we will clear the pointer.
  186. //
  187. if (IrpContext->TeardownFcb != NULL) {
  188. UdfTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), FALSE, &RemovedFcb );
  189. if (!RemovedFcb) {
  190. UdfReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
  191. }
  192. *(IrpContext->TeardownFcb) = NULL;
  193. IrpContext->TeardownFcb = NULL;
  194. }
  195. break;
  196. }
  197. //
  198. // Insert the Irp context in the workqueue.
  199. //
  200. UdfAddToWorkque( IrpContext, Irp );
  201. //
  202. // Otherwise complete the request.
  203. //
  204. } else {
  205. UdfCompleteRequest( IrpContext, Irp, Irp->IoStatus.Status );
  206. }
  207. return;
  208. }
  209. //
  210. // Local support routine
  211. //
  212. VOID
  213. UdfAddToWorkque (
  214. IN PIRP_CONTEXT IrpContext,
  215. IN PIRP Irp
  216. )
  217. /*++
  218. Routine Description:
  219. This routine is called to acually store the posted Irp to the Fsp
  220. workque.
  221. Arguments:
  222. IrpContext - Pointer to the IrpContext to be queued to the Fsp
  223. Irp - I/O Request Packet.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. PVOLUME_DEVICE_OBJECT Vdo;
  229. KIRQL SavedIrql;
  230. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  231. //
  232. // Check if this request has an associated file object, and thus volume
  233. // device object.
  234. //
  235. if (IrpSp->FileObject != NULL) {
  236. Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
  237. VOLUME_DEVICE_OBJECT,
  238. DeviceObject );
  239. //
  240. // Check to see if this request should be sent to the overflow
  241. // queue. If not, then send it off to an exworker thread.
  242. //
  243. KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
  244. if (Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
  245. //
  246. // We cannot currently respond to this IRP so we'll just enqueue it
  247. // to the overflow queue on the volume.
  248. //
  249. InsertTailList( &Vdo->OverflowQueue,
  250. &IrpContext->WorkQueueItem.List );
  251. Vdo->OverflowQueueCount += 1;
  252. KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
  253. return;
  254. } else {
  255. //
  256. // We are going to send this Irp to an ex worker thread so up
  257. // the count.
  258. //
  259. Vdo->PostedRequestCount += 1;
  260. KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
  261. }
  262. }
  263. //
  264. // Send it off.....
  265. //
  266. ExInitializeWorkItem( &IrpContext->WorkQueueItem,
  267. UdfFspDispatch,
  268. IrpContext );
  269. ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
  270. return;
  271. }