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.

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