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.

712 lines
19 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FspDisp.c
  5. Abstract:
  6. This module implements the main dispatch procedure/thread for the RDBSS Fsp
  7. Author:
  8. Joe Linn [JoeLinn] 1-aug-1994
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "NtDspVec.h"
  14. #include <ntddnfs2.h>
  15. #include <ntddmup.h>
  16. //
  17. // Define our local debug trace level
  18. //
  19. #define Dbg (DEBUG_TRACE_FSP_DISPATCHER)
  20. #ifndef MONOLITHIC_MINIRDR
  21. PIO_WORKITEM RxIoWorkItem;
  22. #endif
  23. //
  24. // Internal support routine, spinlock wrapper.
  25. //
  26. PRX_CONTEXT
  27. RxRemoveOverflowEntry (
  28. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  29. IN WORK_QUEUE_TYPE Type
  30. );
  31. #ifdef ALLOC_PRAGMA
  32. #pragma alloc_text(PAGE, RxFspDispatch)
  33. #endif
  34. #ifdef RDBSSLOG
  35. //this stuff must be in nonpaged memory
  36. //// 1 2 3 4 5 6 7
  37. char RxFsp_SurrogateFormat[] = "%S%S%N%N%N%N%N";
  38. //// 2 3 4 5 6 7
  39. char RxFsp_ActualFormat[] = "Fsp %s/%lx %08lx irp %lx thrd %lx #%lx";
  40. #endif //ifdef RDBSSLOG
  41. #ifndef MONOLITHIC_MINIRDR
  42. VOID
  43. RxFspDispatchEx (
  44. IN PDEVICE_OBJECT DeviceObject,
  45. IN PVOID Context
  46. )
  47. /*++
  48. Routine Description:
  49. This routine calls RxFspDispatch which is the main FSP thread routine that
  50. is executed to receive and dispatch IRP requests.
  51. Arguments:
  52. Context - The RxContext being queued to the FSP.
  53. Notes:
  54. None.
  55. --*/
  56. {
  57. RxFspDispatch( Context );
  58. return;
  59. }
  60. #endif
  61. VOID
  62. RxFspDispatch (
  63. IN PVOID Context
  64. )
  65. /*++
  66. Routine Description:
  67. This is the main FSP thread routine that is executed to receive
  68. and dispatch IRP requests. Each FSP thread begins its execution here.
  69. There is one thread created at system initialization time and subsequent
  70. threads created as needed.
  71. Arguments:
  72. Context - The RxContext being queued to the FSP.
  73. Notes:
  74. This routine never exits
  75. --*/
  76. {
  77. NTSTATUS Status;
  78. PRX_CONTEXT RxContext = (PRX_CONTEXT)Context;
  79. RX_TOPLEVELIRP_CONTEXT TopLevelContext;
  80. PRDBSS_DEVICE_OBJECT RxDeviceObject;
  81. WORK_QUEUE_TYPE WorkQueueType;
  82. DWORD CurrentIrql;
  83. PIRP Irp = RxContext->CurrentIrp;
  84. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  85. PFILE_OBJECT FileObject = IrpSp->FileObject;
  86. PAGED_CODE();
  87. CurrentIrql = KeGetCurrentIrql();
  88. //
  89. // If this request has an associated volume device object, remember it.
  90. //
  91. if (FileObject != NULL ) {
  92. RxDeviceObject = CONTAINING_RECORD( IrpSp->DeviceObject, RDBSS_DEVICE_OBJECT, DeviceObject );
  93. //
  94. // currently, we use the wrapper's device object for all throttling.....
  95. //
  96. RxDeviceObject = RxFileSystemDeviceObject;
  97. } else {
  98. RxDeviceObject = NULL;
  99. }
  100. if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE )) {
  101. WorkQueueType = DelayedWorkQueue;
  102. } else if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE )) {
  103. WorkQueueType = CriticalWorkQueue;
  104. } else {
  105. ASSERT(!"Valid RXCONTEXT Work Queue Type");
  106. }
  107. //
  108. // We'll do all of the work within an exception handler that
  109. // will be invoked if ever some underlying operation gets into
  110. // trouble.
  111. //
  112. while (TRUE) {
  113. //
  114. // Grab the current irp
  115. //
  116. Irp = RxContext->CurrentIrp;
  117. RxDbgTrace( 0, Dbg, ("RxFspDispatch: IrpC = 0x%08lx\n", RxContext) );
  118. ASSERT( RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION );
  119. ASSERT( RxContext->PostRequest == FALSE );
  120. RxContext->LastExecutionThread = PsGetCurrentThread();
  121. RxLog(( RxFsp_SurrogateFormat, RxFsp_ActualFormat, RXCONTX_OPERATION_NAME( RxContext->MajorFunction, TRUE ), RxContext->MinorFunction, RxContext, Irp, RxContext->LastExecutionThread, RxContext->SerialNumber ));
  122. RxWmiLog( LOG,
  123. RxFspDispatch,
  124. LOGPTR( RxContext)
  125. LOGPTR( Irp )
  126. LOGPTR( RxContext->LastExecutionThread)
  127. LOGULONG( RxContext->SerialNumber)
  128. LOGUCHAR( RxContext->MinorFunction)
  129. LOGARSTR( RXCONTX_OPERATION_NAME( RxContext->MajorFunction, TRUE ) ) );
  130. //
  131. // Now because we are the Fsp we will force the RxContext to
  132. // indicate true on Wait.
  133. //
  134. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_IN_FSP );
  135. //
  136. // If this Irp was top level, note it in our thread local storage.
  137. //
  138. FsRtlEnterFileSystem();
  139. if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL )) {
  140. RxTryToBecomeTheTopLevelIrp( &TopLevelContext,
  141. (PIRP)FSRTL_FSP_TOP_LEVEL_IRP,
  142. RxContext->RxDeviceObject,
  143. TRUE ); // force
  144. } else {
  145. RxTryToBecomeTheTopLevelIrp( &TopLevelContext,
  146. Irp,
  147. RxContext->RxDeviceObject,
  148. TRUE ); // force
  149. }
  150. try {
  151. ASSERT( RxContext->ResumeRoutine != NULL );
  152. if (FlagOn( RxContext->MinorFunction, IRP_MN_DPC ) && (Irp->Tail.Overlay.Thread == NULL)) {
  153. ASSERT( (RxContext->MajorFunction == IRP_MJ_WRITE) ||
  154. (RxContext->MajorFunction == IRP_MJ_READ) );
  155. Irp->Tail.Overlay.Thread = PsGetCurrentThread();
  156. }
  157. do {
  158. BOOLEAN NoCompletion = BooleanFlagOn( RxContext->Flags, RX_CONTEXT_FLAG_NO_COMPLETE_FROM_FSP );
  159. Status = RxContext->ResumeRoutine( RxContext, Irp );
  160. if (NoCompletion) {
  161. NOTHING;
  162. } else if ((Status != STATUS_PENDING) && (Status != STATUS_RETRY)) {
  163. Status = RxCompleteRequest( RxContext, Status );
  164. }
  165. } while (Status == STATUS_RETRY);
  166. } except( RxExceptionFilter( RxContext, GetExceptionInformation() )) {
  167. //
  168. // We had some trouble trying to perform the requested
  169. // operation, so we'll abort the I/O request with
  170. // the error status that we get back from the
  171. // execption code.
  172. //
  173. (VOID) RxProcessException( RxContext, GetExceptionCode() );
  174. }
  175. RxUnwindTopLevelIrp( &TopLevelContext );
  176. FsRtlExitFileSystem();
  177. //
  178. // If there are any entries on this volume's overflow queue, service
  179. // them.
  180. //
  181. if (RxDeviceObject != NULL) {
  182. //
  183. // We have a volume device object so see if there is any work
  184. // left to do in its overflow queue.
  185. //
  186. RxContext = RxRemoveOverflowEntry( RxDeviceObject,WorkQueueType );
  187. //
  188. // There wasn't an entry, break out of the loop and return to
  189. // the Ex Worker thread.
  190. //
  191. if (RxContext == NULL) {
  192. break;
  193. }
  194. continue;
  195. } else {
  196. break;
  197. }
  198. }
  199. #ifdef DBG
  200. if(KeGetCurrentIrql() >= APC_LEVEL) {
  201. DbgPrint( "High Irql RxContext=%x Irql On Entry=%x\n", RxContext, CurrentIrql);
  202. // DbgBreakPoint();
  203. }
  204. #endif
  205. return;
  206. }
  207. //
  208. // Internal support routine, spinlock wrapper.
  209. //
  210. PRX_CONTEXT
  211. RxRemoveOverflowEntry (
  212. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  213. IN WORK_QUEUE_TYPE WorkQueueType)
  214. {
  215. PRX_CONTEXT RxContext;
  216. KIRQL SavedIrql;
  217. KeAcquireSpinLock( &RxDeviceObject->OverflowQueueSpinLock, &SavedIrql );
  218. if (RxDeviceObject->OverflowQueueCount[WorkQueueType] > 0) {
  219. PVOID Entry;
  220. //
  221. // There is overflow work to do in this volume so we'll
  222. // decrement the Overflow count, dequeue the IRP, and release
  223. // the Event
  224. //
  225. RxDeviceObject->OverflowQueueCount[WorkQueueType] -= 1;
  226. Entry = RemoveHeadList( &RxDeviceObject->OverflowQueue[WorkQueueType] );
  227. //
  228. // Extract the RxContext, Irp, and IrpSp, and loop.
  229. //
  230. RxContext = CONTAINING_RECORD( Entry,
  231. RX_CONTEXT,
  232. OverflowListEntry );
  233. RxContext->OverflowListEntry.Flink = NULL;
  234. ClearFlag( RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE );
  235. } else {
  236. RxContext = NULL;
  237. InterlockedDecrement( &RxDeviceObject->PostedRequestCount[WorkQueueType] );
  238. }
  239. KeReleaseSpinLock( &RxDeviceObject->OverflowQueueSpinLock, SavedIrql );
  240. return RxContext;
  241. }
  242. BOOLEAN
  243. RxCancelOperationInOverflowQueue (
  244. PRX_CONTEXT RxContext
  245. )
  246. /*++
  247. Routine Description:
  248. This routine cancels the operation in the overflow queue
  249. Arguments:
  250. RxContext The context of the operation being synchronized
  251. --*/
  252. {
  253. BOOLEAN CancelledRequest = FALSE;
  254. PRDBSS_DEVICE_OBJECT RxDeviceObject;
  255. KIRQL SavedIrql;
  256. //
  257. // currently, we use the wrapper's device object for all throttling.....
  258. //
  259. RxDeviceObject = RxFileSystemDeviceObject;
  260. KeAcquireSpinLock( &RxDeviceObject->OverflowQueueSpinLock, &SavedIrql );
  261. if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE) &&
  262. (RxContext->OverflowListEntry.Flink != NULL)) {
  263. //
  264. // Remove the entry from the overflow queue
  265. //
  266. RemoveEntryList( &RxContext->OverflowListEntry );
  267. RxContext->OverflowListEntry.Flink = NULL;
  268. if (FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE )) {
  269. RxDeviceObject->OverflowQueueCount[CriticalWorkQueue] -= 1;
  270. } else {
  271. RxDeviceObject->OverflowQueueCount[DelayedWorkQueue] -= 1;
  272. }
  273. ClearFlag( RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE | RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE );
  274. CancelledRequest = TRUE;
  275. }
  276. KeReleaseSpinLock( &RxDeviceObject->OverflowQueueSpinLock, SavedIrql );
  277. if (CancelledRequest) {
  278. RxRemoveOperationFromBlockingQueue( RxContext );
  279. RxCompleteRequest( RxContext, STATUS_CANCELLED );
  280. }
  281. return CancelledRequest;
  282. }
  283. //
  284. // The following constant is the maximum number of ExWorkerThreads that we
  285. // will allow to be servicing a particular target device at any one time.
  286. //
  287. #define FSP_PER_DEVICE_THRESHOLD (1)
  288. VOID
  289. RxPrePostIrp (
  290. IN PVOID Context,
  291. IN PIRP Irp
  292. )
  293. /*++
  294. Routine Description:
  295. This routine performs any neccessary work before RxStatus(PENDING) is
  296. returned with the Fsd thread. This routine is called within the
  297. filesystem and by the oplock package. The main issue is that we are about
  298. to leave the user's process so we need to get a systemwide address for
  299. anything in his address space that we require.
  300. Arguments:
  301. Context - Pointer to the RxContext to be queued to the Fsp
  302. Irp - I/O Request Packet.
  303. Return Value:
  304. None.
  305. --*/
  306. {
  307. PRX_CONTEXT RxContext = (PRX_CONTEXT) Context;
  308. PIO_STACK_LOCATION IrpSp;
  309. //
  310. // If there is no Irp, we are done.
  311. //
  312. if (Irp == NULL) {
  313. return;
  314. }
  315. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  316. if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED )) {
  317. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED );
  318. //
  319. // We need to lock the user's buffer, unless this is an MDL-read,
  320. // in which case there is no user buffer.
  321. //
  322. // **** we need a better test than non-MDL (read or write)!
  323. //
  324. if ((RxContext->MajorFunction == IRP_MJ_READ) || (RxContext->MajorFunction == IRP_MJ_WRITE)) {
  325. //
  326. // If not an Mdl request, lock the user's buffer.
  327. //
  328. if (!FlagOn( RxContext->MinorFunction, IRP_MN_MDL )) {
  329. RxLockUserBuffer( RxContext,
  330. Irp,
  331. (RxContext->MajorFunction == IRP_MJ_READ) ? IoWriteAccess : IoReadAccess,
  332. IrpSp->Parameters.Write.Length );
  333. }
  334. //
  335. // We also need to check whether this is a query file operation.
  336. //
  337. } else if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
  338. (RxContext->MinorFunction == IRP_MN_QUERY_DIRECTORY)) {
  339. RxLockUserBuffer( RxContext,
  340. Irp,
  341. IoWriteAccess,
  342. IrpSp->Parameters.QueryDirectory.Length );
  343. //
  344. // We also need to check whether this is a query ea operation.
  345. //
  346. } else if (RxContext->MajorFunction == IRP_MJ_QUERY_EA) {
  347. RxLockUserBuffer( RxContext,
  348. Irp,
  349. IoWriteAccess,
  350. IrpSp->Parameters.QueryEa.Length );
  351. //
  352. // We also need to check whether this is a set ea operation.
  353. //
  354. } else if (RxContext->MajorFunction == IRP_MJ_SET_EA) {
  355. RxLockUserBuffer( RxContext,
  356. Irp,
  357. IoReadAccess,
  358. IrpSp->Parameters.SetEa.Length );
  359. }
  360. //
  361. // Mark that we've already returned pending to the user
  362. //
  363. IoMarkIrpPending( Irp );
  364. }
  365. return;
  366. }
  367. #ifdef RDBSSLOG
  368. //this stuff must be in nonpaged memory
  369. //// 1 2 3 4 5 6 7
  370. char RxFsdPost_SurrogateFormat[] = "%S%S%N%N%N%N%N";
  371. //// 2 3 4 5 6 7
  372. char RxFsdPost_ActualFormat[] = "POST %s/%lx %08lx irp %lx thrd %lx #%lx";
  373. #endif //ifdef RDBSSLOG
  374. NTSTATUS
  375. RxFsdPostRequest (
  376. IN PRX_CONTEXT RxContext
  377. )
  378. /*++
  379. Routine Description:
  380. This routine enqueues the request packet specified by RxContext to the
  381. Ex Worker threads. This is a FSD routine.
  382. Arguments:
  383. RxContext - Pointer to the RxContext to be queued to the Fsp
  384. Return Value:
  385. RxStatus(PENDING)
  386. --*/
  387. {
  388. PIRP Irp = RxContext->CurrentIrp;
  389. if(!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED )) {
  390. RxPrePostIrp( RxContext, Irp );
  391. }
  392. RxLog(( RxFsdPost_SurrogateFormat,
  393. RxFsdPost_ActualFormat,
  394. RXCONTX_OPERATION_NAME( RxContext->MajorFunction, TRUE ),
  395. RxContext->MinorFunction,
  396. RxContext,
  397. RxContext->CurrentIrp,
  398. RxContext->LastExecutionThread,
  399. RxContext->SerialNumber ));
  400. RxWmiLog( LOG,
  401. RxFsdPostRequest,
  402. LOGPTR( RxContext )
  403. LOGPTR( RxContext->CurrentIrp )
  404. LOGPTR( RxContext->LastExecutionThread )
  405. LOGULONG( RxContext->SerialNumber )
  406. LOGUCHAR( RxContext->MinorFunction )
  407. LOGARSTR( RXCONTX_OPERATION_NAME( RxContext->MajorFunction,TRUE ) ) );
  408. RxAddToWorkque( RxContext, Irp );
  409. return STATUS_PENDING;
  410. }
  411. VOID
  412. RxAddToWorkque (
  413. IN PRX_CONTEXT RxContext,
  414. IN PIRP Irp
  415. )
  416. /*++
  417. Routine Description:
  418. This routine is called to acually store the posted Irp to the Fsp
  419. workque.
  420. Arguments:
  421. RxContext - Pointer to the RxContext to be queued to the Fsp
  422. Irp - I/O Request Packet.
  423. Return Value:
  424. None.
  425. --*/
  426. {
  427. KIRQL SavedIrql;
  428. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  429. PFILE_OBJECT FileObject = IrpSp->FileObject;
  430. WORK_QUEUE_TYPE WorkQueueType;
  431. BOOLEAN PostToWorkerThread = FALSE;
  432. ULONG IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  433. //
  434. // Send it off.....
  435. //
  436. RxContext->PostRequest = FALSE;
  437. //
  438. // Check if this request has an associated file object, and thus volume
  439. // device object.
  440. //
  441. if ((RxContext->MajorFunction == IRP_MJ_DEVICE_CONTROL) &&
  442. (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH)) {
  443. WorkQueueType = DelayedWorkQueue;
  444. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_FSP_DELAYED_OVERFLOW_QUEUE );
  445. } else {
  446. WorkQueueType = CriticalWorkQueue;
  447. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_FSP_CRITICAL_OVERFLOW_QUEUE );
  448. }
  449. if (FileObject != NULL) {
  450. PRDBSS_DEVICE_OBJECT RxDeviceObject;
  451. LONG RequestCount;
  452. RxDeviceObject = CONTAINING_RECORD( IrpSp->DeviceObject, RDBSS_DEVICE_OBJECT, DeviceObject );
  453. //
  454. // currently, we use the wrapper's device object for all throttling.....
  455. //
  456. RxDeviceObject = RxFileSystemDeviceObject;
  457. //
  458. // Check to see if this request should be sent to the overflow
  459. // queue. If not, then send it off to an exworker thread.
  460. //
  461. KeAcquireSpinLock( &RxDeviceObject->OverflowQueueSpinLock, &SavedIrql );
  462. RequestCount = InterlockedIncrement(&RxDeviceObject->PostedRequestCount[WorkQueueType]);
  463. PostToWorkerThread = (RequestCount > FSP_PER_DEVICE_THRESHOLD);
  464. if (PostToWorkerThread) {
  465. //
  466. // We cannot currently respond to this IRP so we'll just enqueue it
  467. // to the overflow queue on the volume.
  468. //
  469. InterlockedDecrement( &RxDeviceObject->PostedRequestCount[WorkQueueType] );
  470. InsertTailList( &RxDeviceObject->OverflowQueue[WorkQueueType],
  471. &RxContext->OverflowListEntry );
  472. RxDeviceObject->OverflowQueueCount[WorkQueueType] += 1;
  473. KeReleaseSpinLock( &RxDeviceObject->OverflowQueueSpinLock, SavedIrql );
  474. return;
  475. } else {
  476. KeReleaseSpinLock( &RxDeviceObject->OverflowQueueSpinLock, SavedIrql );
  477. }
  478. } else {
  479. PostToWorkerThread = TRUE;
  480. }
  481. #ifndef MONOLITHIC_MINIRDR
  482. IoQueueWorkItem( RxIoWorkItem, RxFspDispatchEx, WorkQueueType, RxContext );
  483. #else
  484. ExInitializeWorkItem( &RxContext->WorkQueueItem, RxFspDispatch, RxContext );
  485. ExQueueWorkItem( (PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, WorkQueueType );
  486. #endif
  487. return;
  488. }