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.

368 lines
7.8 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 Fat File
  7. system.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Gary Kimura [GaryKi] 15-Jan-1990
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "FatProcs.h"
  15. //
  16. // The following constant is the maximum number of ExWorkerThreads that we
  17. // will allow to be servicing a particular target device at any one time.
  18. //
  19. #define FSP_PER_DEVICE_THRESHOLD (2)
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, FatOplockComplete)
  22. #pragma alloc_text(PAGE, FatPrePostIrp)
  23. #endif
  24. VOID
  25. FatOplockComplete (
  26. IN PVOID Context,
  27. IN PIRP Irp
  28. )
  29. /*++
  30. Routine Description:
  31. This routine is called by the oplock package when an oplock break has
  32. completed, allowing an Irp to resume execution. If the status in
  33. the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
  34. Otherwise we complete the Irp with the status in the Irp.
  35. Arguments:
  36. Context - Pointer to the IrpContext to be queued to the Fsp
  37. Irp - I/O Request Packet.
  38. Return Value:
  39. None.
  40. --*/
  41. {
  42. //
  43. // Check on the return value in the Irp.
  44. //
  45. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  46. //
  47. // Insert the Irp context in the workqueue.
  48. //
  49. FatAddToWorkque( (PIRP_CONTEXT) Context, Irp );
  50. //
  51. // Otherwise complete the request.
  52. //
  53. } else {
  54. FatCompleteRequest( (PIRP_CONTEXT) Context, Irp, Irp->IoStatus.Status );
  55. }
  56. return;
  57. }
  58. VOID
  59. FatPrePostIrp (
  60. IN PVOID Context,
  61. IN PIRP Irp
  62. )
  63. /*++
  64. Routine Description:
  65. This routine performs any neccessary work before STATUS_PENDING is
  66. returned with the Fsd thread. This routine is called within the
  67. filesystem and by the oplock package.
  68. Arguments:
  69. Context - Pointer to the IrpContext to be queued to the Fsp
  70. Irp - I/O Request Packet.
  71. Return Value:
  72. None.
  73. --*/
  74. {
  75. PIO_STACK_LOCATION IrpSp;
  76. PIRP_CONTEXT IrpContext;
  77. //
  78. // If there is no Irp, we are done.
  79. //
  80. if (Irp == NULL) {
  81. return;
  82. }
  83. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  84. IrpContext = (PIRP_CONTEXT) Context;
  85. //
  86. // If there is a STACK FatIoContext pointer, clean and NULL it.
  87. //
  88. if ((IrpContext->FatIoContext != NULL) &&
  89. FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
  90. ClearFlag(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT);
  91. IrpContext->FatIoContext = NULL;
  92. }
  93. //
  94. // We need to lock the user's buffer, unless this is an MDL-read,
  95. // in which case there is no user buffer.
  96. //
  97. // **** we need a better test than non-MDL (read or write)!
  98. if (IrpContext->MajorFunction == IRP_MJ_READ ||
  99. IrpContext->MajorFunction == IRP_MJ_WRITE) {
  100. //
  101. // If not an Mdl request, lock the user's buffer.
  102. //
  103. if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
  104. FatLockUserBuffer( IrpContext,
  105. Irp,
  106. (IrpContext->MajorFunction == IRP_MJ_READ) ?
  107. IoWriteAccess : IoReadAccess,
  108. (IrpContext->MajorFunction == IRP_MJ_READ) ?
  109. IrpSp->Parameters.Read.Length : IrpSp->Parameters.Write.Length );
  110. }
  111. //
  112. // We also need to check whether this is a query file operation.
  113. //
  114. } else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL
  115. && IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
  116. FatLockUserBuffer( IrpContext,
  117. Irp,
  118. IoWriteAccess,
  119. IrpSp->Parameters.QueryDirectory.Length );
  120. //
  121. // We also need to check whether this is a query ea operation.
  122. //
  123. } else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {
  124. FatLockUserBuffer( IrpContext,
  125. Irp,
  126. IoWriteAccess,
  127. IrpSp->Parameters.QueryEa.Length );
  128. //
  129. // We also need to check whether this is a set ea operation.
  130. //
  131. } else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {
  132. FatLockUserBuffer( IrpContext,
  133. Irp,
  134. IoReadAccess,
  135. IrpSp->Parameters.SetEa.Length );
  136. //
  137. // These two FSCTLs use neither I/O, so check for them.
  138. //
  139. } else if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
  140. (IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) &&
  141. ((IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) ||
  142. (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS))) {
  143. FatLockUserBuffer( IrpContext,
  144. Irp,
  145. IoWriteAccess,
  146. IrpSp->Parameters.FileSystemControl.OutputBufferLength );
  147. }
  148. //
  149. // Mark that we've already returned pending to the user
  150. //
  151. IoMarkIrpPending( Irp );
  152. return;
  153. }
  154. NTSTATUS
  155. FatFsdPostRequest(
  156. IN PIRP_CONTEXT IrpContext,
  157. IN PIRP Irp
  158. )
  159. /*++
  160. Routine Description:
  161. This routine enqueues the request packet specified by IrpContext to the
  162. Ex Worker threads. This is a FSD routine.
  163. Arguments:
  164. IrpContext - Pointer to the IrpContext to be queued to the Fsp
  165. Irp - I/O Request Packet, or NULL if it has already been completed.
  166. Return Value:
  167. STATUS_PENDING
  168. --*/
  169. {
  170. ASSERT( ARGUMENT_PRESENT(Irp) );
  171. ASSERT( IrpContext->OriginatingIrp == Irp );
  172. FatPrePostIrp( IrpContext, Irp );
  173. FatAddToWorkque( IrpContext, Irp );
  174. //
  175. // And return to our caller
  176. //
  177. return STATUS_PENDING;
  178. }
  179. //
  180. // Local support routine.
  181. //
  182. VOID
  183. FatAddToWorkque (
  184. IN PIRP_CONTEXT IrpContext,
  185. IN PIRP Irp
  186. )
  187. /*++
  188. Routine Description:
  189. This routine is called to acually store the posted Irp to the Fsp
  190. workque.
  191. Arguments:
  192. IrpContext - Pointer to the IrpContext to be queued to the Fsp
  193. Irp - I/O Request Packet.
  194. Return Value:
  195. None.
  196. --*/
  197. {
  198. KIRQL SavedIrql;
  199. PIO_STACK_LOCATION IrpSp;
  200. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  201. //
  202. // Check if this request has an associated file object, and thus volume
  203. // device object.
  204. //
  205. if ( IrpSp->FileObject != NULL ) {
  206. PVOLUME_DEVICE_OBJECT Vdo;
  207. Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
  208. VOLUME_DEVICE_OBJECT,
  209. DeviceObject );
  210. //
  211. // Check to see if this request should be sent to the overflow
  212. // queue. If not, then send it off to an exworker thread.
  213. //
  214. KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
  215. if ( Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
  216. //
  217. // We cannot currently respond to this IRP so we'll just enqueue it
  218. // to the overflow queue on the volume.
  219. //
  220. InsertTailList( &Vdo->OverflowQueue,
  221. &IrpContext->WorkQueueItem.List );
  222. Vdo->OverflowQueueCount += 1;
  223. KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
  224. return;
  225. } else {
  226. //
  227. // We are going to send this Irp to an ex worker thread so up
  228. // the count.
  229. //
  230. Vdo->PostedRequestCount += 1;
  231. KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
  232. }
  233. }
  234. //
  235. // Send it off.....
  236. //
  237. ExInitializeWorkItem( &IrpContext->WorkQueueItem,
  238. FatFspDispatch,
  239. IrpContext );
  240. ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
  241. return;
  242. }