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.

3125 lines
102 KiB

  1. /*++ Copyright (c) 1999 Microsoft Corporation
  2. Module Name:
  3. umrx.c
  4. Abstract:
  5. This module defines the types and functions which make up the reflector
  6. library. These functions are used by the miniredirs to reflect calls upto
  7. the user mode.
  8. Author:
  9. Rohan Kumar [rohank] 15-March-1999
  10. Notes:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <dfsfsctl.h>
  15. #include "reflctor.h"
  16. //
  17. // Mentioned below are the prototypes of functions that are used only within
  18. // this module (file). These functions should not be exposed outside.
  19. //
  20. NTSTATUS
  21. UMRxCompleteUserModeRequest (
  22. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  23. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItem,
  24. IN ULONG WorkItemLength,
  25. OUT PIO_STATUS_BLOCK IoStatus
  26. );
  27. NTSTATUS
  28. UMRxCompleteUserModeErroneousRequest(
  29. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  30. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  31. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  32. IN ULONG WorkItemHeaderLength
  33. );
  34. NTSTATUS
  35. UMRxAcquireMidAndFormatHeader (
  36. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  37. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  38. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItem
  39. );
  40. NTSTATUS
  41. UMRxPrepareUserModeRequestBuffer (
  42. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  43. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  44. OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItem,
  45. IN ULONG WorkItemLength,
  46. OUT PIO_STATUS_BLOCK IoStatus
  47. );
  48. NTSTATUS
  49. UMRxVerifyHeader (
  50. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  51. IN PUMRX_USERMODE_WORKITEM_HEADER WorkItem,
  52. IN ULONG ReassignmentCmd,
  53. OUT PUMRX_ASYNCENGINE_CONTEXT *capturedAsyncEngineContext
  54. );
  55. NTSTATUS
  56. UMRxEnqueueUserModeCallUp(
  57. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  58. );
  59. PUMRX_SHARED_HEAP
  60. UMRxAddSharedHeap(
  61. PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  62. SIZE_T HeapSize
  63. );
  64. PUMRX_ASYNCENGINE_CONTEXT
  65. UMRxCreateAsyncEngineContext(
  66. IN PRX_CONTEXT RxContext,
  67. IN ULONG SizeToAllocate
  68. );
  69. #ifdef ALLOC_PRAGMA
  70. #pragma alloc_text(PAGE, UMRxResumeAsyncEngineContext)
  71. #pragma alloc_text(PAGE, UMRxSubmitAsyncEngUserModeRequest)
  72. #pragma alloc_text(PAGE, UMRxCreateAsyncEngineContext)
  73. #pragma alloc_text(PAGE, UMRxFinalizeAsyncEngineContext)
  74. #pragma alloc_text(PAGE, UMRxPostOperation)
  75. #pragma alloc_text(PAGE, UMRxAcquireMidAndFormatHeader)
  76. #pragma alloc_text(PAGE, UMRxPrepareUserModeRequestBuffer)
  77. #pragma alloc_text(PAGE, UMRxCompleteUserModeErroneousRequest)
  78. #pragma alloc_text(PAGE, UMRxVerifyHeader)
  79. #pragma alloc_text(PAGE, UMRxCompleteUserModeRequest)
  80. #pragma alloc_text(PAGE, UMRxEnqueueUserModeCallUp)
  81. #pragma alloc_text(PAGE, UMRxAssignWork)
  82. #pragma alloc_text(PAGE, UMRxReleaseCapturedThreads)
  83. #pragma alloc_text(PAGE, UMRxAllocateSecondaryBuffer)
  84. #pragma alloc_text(PAGE, UMRxFreeSecondaryBuffer)
  85. #pragma alloc_text(PAGE, UMRxAddSharedHeap)
  86. #pragma alloc_text(PAGE, UMRxInitializeDeviceObject)
  87. #pragma alloc_text(PAGE, UMRxCleanUpDeviceObject)
  88. #pragma alloc_text(PAGE, UMRxImpersonateClient)
  89. #pragma alloc_text(PAGE, UMRxAsyncEngOuterWrapper)
  90. #pragma alloc_text(PAGE, UMRxReadDWORDFromTheRegistry)
  91. #endif
  92. #if DBG
  93. #ifdef ALLOC_PRAGMA
  94. #pragma alloc_text(PAGE, __UMRxAsyncEngAssertConsistentLinkage)
  95. #pragma alloc_text(PAGE, UMRxAsyncEngShortStatus)
  96. #pragma alloc_text(PAGE, UMRxAsyncEngUpdateHistory)
  97. #endif
  98. #endif
  99. //
  100. // The global list of all the currently active AsyncEngineContexts and the
  101. // resource that is used to synchronize access to it.
  102. //
  103. LIST_ENTRY UMRxAsyncEngineContextList;
  104. ERESOURCE UMRxAsyncEngineContextListLock;
  105. //
  106. // Implementation of functions begins here.
  107. //
  108. #if DBG
  109. VOID
  110. __UMRxAsyncEngAssertConsistentLinkage(
  111. PSZ MsgPrefix,
  112. PSZ File,
  113. unsigned Line,
  114. PRX_CONTEXT RxContext,
  115. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  116. ULONG Flags
  117. )
  118. /*++
  119. Routine Description:
  120. This routine performs a variety of checks to ensure that the linkage between
  121. the RxContext and the AsyncEngineContext is correct and that various fields
  122. have correct values. If anything is bad, print stuff out and break into the
  123. debugger.
  124. Arguments:
  125. MsgPrefix - An identifying message for debugging purposes.
  126. RxContext - The RDBSS context.
  127. AsyncEngineContext - The exchange to be conducted.
  128. Flags - The flags associated with the AsyncEngineContext.
  129. Return Value:
  130. none
  131. Notes:
  132. --*/
  133. {
  134. ULONG errors = 0;
  135. PAGED_CODE();
  136. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  137. ("%ld: Entering __UMRxAsyncEngAssertConsistentLinkage!!!!.\n",
  138. PsGetCurrentThreadId()));
  139. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  140. ("%ld: __UMRxAsyncEngAssertConsistentLinkage: "
  141. "AsyncEngineContext: %08lx.\n",
  142. PsGetCurrentThreadId(), AsyncEngineContext));
  143. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  144. ("%ld: __UMRxAsyncEngAssertConsistentLinkage: "
  145. "RxContext->MRxContext[0]: %08lx.\n",
  146. PsGetCurrentThreadId(), RxContext->MRxContext[0]));
  147. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  148. ("%ld: __UMRxAsyncEngAssertConsistentLinkage: "
  149. "RxContext: %08lx.\n", PsGetCurrentThreadId(), RxContext));
  150. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  151. ("%ld: __UMRxAsyncEngAssertConsistentLinkage: "
  152. "AsyncEngineContext->RxContext = %08lx.\n",
  153. PsGetCurrentThreadId(), AsyncEngineContext->RxContext));
  154. P__ASSERT(AsyncEngineContext->SerialNumber == RxContext->SerialNumber);
  155. P__ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
  156. P__ASSERT(NodeType(AsyncEngineContext) == UMRX_NTC_ASYNCENGINE_CONTEXT);
  157. P__ASSERT(AsyncEngineContext->RxContext == RxContext);
  158. P__ASSERT(AsyncEngineContext == (PUMRX_ASYNCENGINE_CONTEXT)RxContext->MRxContext[0]);
  159. if (!FlagOn(Flags, AECTX_CHKLINKAGE_FLAG_NO_REQPCKT_CHECK)) {
  160. // P__ASSERT(AsyncEngineContext->RxContextCapturedRequestPacket == RxContext->CurrentIrp);
  161. }
  162. if (errors == 0) {
  163. return;
  164. }
  165. UMRxDbgTrace(UMRX_TRACE_ERROR,
  166. ("%ld: ERROR: __UMRxAsyncEngAssertConsistentLinkage: %s "
  167. "%d errors in file %s at line %d\n",
  168. PsGetCurrentThreadId(), MsgPrefix, errors, File, Line));
  169. DbgBreakPoint();
  170. return;
  171. }
  172. ULONG
  173. UMRxAsyncEngShortStatus(
  174. IN ULONG Status
  175. )
  176. /*++
  177. Routine Description:
  178. This routine calculates the short status.
  179. Arguments:
  180. Status - The status value passed in.
  181. Return Value:
  182. ULONG - The short status for the value passed in.
  183. --*/
  184. {
  185. ULONG ShortStatus;
  186. PAGED_CODE();
  187. ShortStatus = Status & 0xc0003fff;
  188. ShortStatus = ShortStatus | (ShortStatus >> 16);
  189. return(ShortStatus);
  190. }
  191. VOID
  192. UMRxAsyncEngUpdateHistory(
  193. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  194. ULONG Tag1,
  195. ULONG Tag2
  196. )
  197. /*++
  198. Routine Description:
  199. This routine updates the histroy of the AsynEngineContext.
  200. Arguments:
  201. AsyncEngineContext - The exchange to be conducted.
  202. Tag1, Tag2 - Tags used for the update.
  203. Return Value:
  204. RXSTATUS - The return status for the operation
  205. --*/
  206. {
  207. ULONG MyIndex, Long0, Long1;
  208. PAGED_CODE();
  209. MyIndex = InterlockedIncrement(&AsyncEngineContext->History.Next);
  210. MyIndex = (MyIndex - 1) & (UMRX_ASYNCENG_HISTORY_SIZE - 1);
  211. Long0 = (Tag1 << 16) | (Tag2 & 0xffff);
  212. Long1 = (UMRxAsyncEngShortStatus(AsyncEngineContext->Status) << 16)
  213. | AsyncEngineContext->Flags;
  214. AsyncEngineContext->History.Markers[MyIndex].Longs[0] = Long0;
  215. AsyncEngineContext->History.Markers[MyIndex].Longs[1] = Long1;
  216. }
  217. #endif
  218. NTSTATUS
  219. UMRxResumeAsyncEngineContext(
  220. IN OUT PRX_CONTEXT RxContext
  221. )
  222. /*++
  223. Routine Description:
  224. This routine resumes processing on an exchange. This is called when work is
  225. required to finish processing a request that cannot be completed at DPC
  226. level. This happens either because the parse routine needs access to
  227. structures that are not locks OR because the operation is asynchronous and
  228. there maybe more work to be done. The two cases are regularized by delaying
  229. the parse if we know that we're going to post: this is indicated by the
  230. presense of a resume routine.
  231. Arguments:
  232. RxContext - The RDBSS context of the operation.
  233. Return Value:
  234. RXSTATUS - The return status for the operation
  235. Notes:
  236. --*/
  237. {
  238. NTSTATUS NtStatus = STATUS_SUCCESS;
  239. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = NULL;
  240. PAGED_CODE();
  241. AsyncEngineContext = (PUMRX_ASYNCENGINE_CONTEXT)RxContext->MRxContext[0];
  242. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  243. ("%ld: Entering UMRxResumeAsyncEngineContext.\n",
  244. PsGetCurrentThreadId()));
  245. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  246. ("%ld: UMRxResumeAsyncEngineContext: "
  247. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  248. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  249. UMRxAsyncEngAssertConsistentLinkage("UMRxResumeAsyncEngineContext: ",
  250. AECTX_CHKLINKAGE_FLAG_NO_REQPCKT_CHECK);
  251. NtStatus = AsyncEngineContext->Status;
  252. UPDATE_HISTORY_WITH_STATUS('0c');
  253. UPDATE_HISTORY_WITH_STATUS('4c');
  254. //
  255. // Remove my references which were added when the AsyncEngineContext was
  256. // placed on the KQueue. If I'm the last guy then finalize.
  257. //
  258. UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  259. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  260. ("%ld: Leaving UMRxResumeAsyncEngineContext with NtStatus = "
  261. "%08lx.\n", PsGetCurrentThreadId(), NtStatus));
  262. return(NtStatus);
  263. }
  264. NTSTATUS
  265. UMRxSubmitAsyncEngUserModeRequest(
  266. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  267. IN PUMRX_ASYNCENG_USERMODE_FORMAT_ROUTINE FormatRoutine,
  268. IN PUMRX_ASYNCENG_USERMODE_PRECOMPLETION_ROUTINE PrecompletionRoutine
  269. )
  270. /*++
  271. Routine Description:
  272. This routine sets some fields (see below) in the AsyncEnineContext structure
  273. and calls the UMRxEnqueueUserModeCallUp function.
  274. Arguments:
  275. RxContext - The RDBSS context.
  276. AsyncEngineContext - The exchange to be conducted.
  277. FormatRoutine - The routine that formats the arguments of the I/O request
  278. which is handled by a usermode process.
  279. PrecompletionRoutine - The routine that handles the post processing of an
  280. I/O request. By post processing we mean after the
  281. request returns from the user mode.
  282. Return Value:
  283. RXSTATUS - The return status for the operation
  284. --*/
  285. {
  286. NTSTATUS NtStatus = STATUS_SUCCESS;
  287. BOOLEAN AsyncOperation = FlagOn(AsyncEngineContext->Flags,
  288. UMRX_ASYNCENG_CTX_FLAG_ASYNC_OPERATION);
  289. PAGED_CODE();
  290. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  291. ("%ld: Entering UMRxSubmitAsyncEngUserModeRequest!!!!\n",
  292. PsGetCurrentThreadId()));
  293. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  294. ("%ld: UMRxSubmitAsyncEngUserModeRequest: AsyncEngineContext:"
  295. " %08lx, RxContext: %08lx.\n",
  296. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  297. UMRxAsyncEngAssertConsistentLinkage("UMRxSubmitAsyncEngUserModeRequest:", 0);
  298. //
  299. // Set the Format, Precompletion and Secondary routines of the context.
  300. //
  301. AsyncEngineContext->UserMode.FormatRoutine = FormatRoutine;
  302. AsyncEngineContext->UserMode.PrecompletionRoutine = PrecompletionRoutine;
  303. if (AsyncOperation) {
  304. AsyncEngineContext->AsyncOperation = TRUE;
  305. }
  306. KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE);
  307. //
  308. // We need to add a reference to the AsyncEngineContext before adding it to
  309. // the Device object's KQueue.
  310. //
  311. InterlockedIncrement( &(AsyncEngineContext->NodeReferenceCount) );
  312. UPDATE_HISTORY_2SHORTS('eo', AsyncOperation?'!!':0);
  313. DEBUG_ONLY_CODE(InterlockedIncrement(&AsyncEngineContext->History.Submits);)
  314. //
  315. // Queue up the usermode request.
  316. //
  317. NtStatus = UMRxEnqueueUserModeCallUp(UMRX_ASYNCENGINE_ARGUMENTS);
  318. if (NtStatus != STATUS_PENDING) {
  319. BOOLEAN ReturnVal = FALSE;
  320. //
  321. // Too bad. We couldn't queue the request. Remove our reference on the
  322. // AsyncEngineContext and leave.
  323. //
  324. UMRxDbgTrace(UMRX_TRACE_ERROR,
  325. ("%ld: ERROR: UMRxSubmitAsyncEngUserModeRequest/"
  326. "UMRxEnqueueUserModeCallUp: NtStatus = %08lx.\n",
  327. PsGetCurrentThreadId(), NtStatus));
  328. ReturnVal = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  329. ASSERT(!ReturnVal);
  330. AsyncEngineContext->Status = NtStatus;
  331. return NtStatus;
  332. }
  333. //
  334. // If this is an Async operation, we set this information in the context
  335. // and leave right away.
  336. //
  337. if (AsyncOperation) {
  338. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  339. ("%ld: UMRxSubmitAsyncEngUserModeRequest: "
  340. "Async Operation!!\n", PsGetCurrentThreadId()));
  341. goto EXIT_THE_FUNCTION;
  342. }
  343. UPDATE_HISTORY_WITH_STATUS('1o');
  344. RxWaitSync(RxContext);
  345. UMRxAsyncEngAssertConsistentLinkage("BeforeResumeAsyncEngineContext: ", 0);
  346. NtStatus = UMRxResumeAsyncEngineContext(RxContext);
  347. UPDATE_HISTORY_WITH_STATUS('9o');
  348. EXIT_THE_FUNCTION:
  349. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  350. ("%ld: Leaving UMRxSubmitAsyncEngUserModeRequest with "
  351. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  352. return(NtStatus);
  353. }
  354. PUMRX_ASYNCENGINE_CONTEXT
  355. UMRxCreateAsyncEngineContext(
  356. IN PRX_CONTEXT RxContext,
  357. IN ULONG SizeToAllocate
  358. )
  359. /*++
  360. Routine Description:
  361. This routine allocates and initializes a miniredir's context.
  362. Arguments:
  363. RxContext - The RDBSS context.
  364. SizeToAllocate - The size to allocate for the new context. This value is
  365. equal to the size of the miniredirs context which
  366. encapsulates the AsynEngineContext.
  367. Return Value:
  368. A miniredir context buffer ready to go, OR NULL.
  369. Notes:
  370. --*/
  371. {
  372. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = NULL;
  373. BOOLEAN ReadWriteIrp = FALSE;
  374. PAGED_CODE();
  375. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  376. ("%ld: Entering UMRxCreateAsyncEngineContext!!!!\n",
  377. PsGetCurrentThreadId()));
  378. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  379. ("%ld: UMRxCreateAsyncEngineContext: RxContext: %08lx.\n",
  380. PsGetCurrentThreadId(), RxContext));
  381. //
  382. // Allocate the miniredir context. If the resources are unavailable, then
  383. // return NULL.
  384. //
  385. AsyncEngineContext = (PUMRX_ASYNCENGINE_CONTEXT)
  386. RxAllocatePoolWithTag(NonPagedPool,
  387. SizeToAllocate,
  388. UMRX_ASYNCENGINECONTEXT_POOLTAG);
  389. if (AsyncEngineContext == NULL) {
  390. UMRxDbgTrace(UMRX_TRACE_ERROR,
  391. ("%ld: ERROR: UMRxCreateAsyncEngineContext/"
  392. "RxAllocatePoolWithTag.\n", PsGetCurrentThreadId()));
  393. return ((PUMRX_ASYNCENGINE_CONTEXT)NULL);
  394. }
  395. //
  396. // Initialize the header of the new (context) node.
  397. //
  398. ZeroAndInitializeNodeType(AsyncEngineContext,
  399. UMRX_NTC_ASYNCENGINE_CONTEXT,
  400. SizeToAllocate);
  401. //
  402. // Place a reference on the context until we are finished.
  403. //
  404. InterlockedIncrement( &(AsyncEngineContext->NodeReferenceCount) );
  405. DEBUG_ONLY_CODE(AsyncEngineContext->SerialNumber = RxContext->SerialNumber);
  406. //
  407. // Place a reference on the RxContext until we are finished.
  408. //
  409. InterlockedIncrement( &(RxContext->ReferenceCount) );
  410. //
  411. // Capture the RxContext.
  412. //
  413. AsyncEngineContext->RxContext = RxContext;
  414. InitializeListHead( &(AsyncEngineContext->AllocationList) );
  415. //
  416. // Capture the IRP.
  417. //
  418. DEBUG_ONLY_CODE(AsyncEngineContext->RxContextCapturedRequestPacket
  419. = RxContext->CurrentIrp);
  420. //
  421. // Save MRxContext[0] incase we use it. The saved context is restored
  422. // just before returning back to RDBSS. This is done because the RDBSS
  423. // may have used MRxContext[0] for storing some information.
  424. //
  425. AsyncEngineContext->SavedMinirdrContextPtr = RxContext->MRxContext[0];
  426. RxContext->MRxContext[0] = (PVOID)AsyncEngineContext;
  427. //
  428. // If this is a Read or a Write IRP, we need to set ReadWriteIrp to TRUE.
  429. //
  430. if ( (RxContext->MajorFunction == IRP_MJ_READ) || (RxContext->MajorFunction == IRP_MJ_WRITE) ) {
  431. ReadWriteIrp = TRUE;
  432. }
  433. //
  434. // If ReadWriteIrp is TRUE, then we do not add the AsyncEngineContext that
  435. // was created to the global UMRxAsyncEngineContextList. This is because
  436. // we do not cancel read/write operations in the DAV Redir, so there is no
  437. // point in adding them to this list. Also, if the MappedPageWriter thread
  438. // is blocked on acquiring the UMRxAsyncEngineContextListLock, it can cause
  439. // a deadlock since the thread that has acquired the lock could be waiting
  440. // for the MM to free up some pages. MM (in this case) ofcourse is waiting
  441. // for the MappedPageWriter to finish.
  442. //
  443. if (ReadWriteIrp == FALSE) {
  444. //
  445. // Add the context to the global UMRxAsyncEngineContextList. We need to
  446. // synchronize this operation.
  447. //
  448. ExAcquireResourceExclusiveLite(&(UMRxAsyncEngineContextListLock), TRUE);
  449. InsertHeadList(&(UMRxAsyncEngineContextList), &(AsyncEngineContext->ActiveContextsListEntry));
  450. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  451. //
  452. // Set the current system time as the creation time of the context.
  453. //
  454. KeQueryTickCount( &(AsyncEngineContext->CreationTimeInTickCount) );
  455. }
  456. return(AsyncEngineContext);
  457. }
  458. BOOLEAN
  459. UMRxFinalizeAsyncEngineContext(
  460. IN OUT PUMRX_ASYNCENGINE_CONTEXT *AEContext
  461. )
  462. /*++
  463. Routine Description:
  464. This finalizes an AsyncEngineContext. If the reference on the context after
  465. the finalization is zero, it is freed. This function is not pagable. See
  466. below for details.
  467. Arguments:
  468. AEContext - Pointer to the address of the AECTX to be finalized.
  469. Return Value:
  470. TRUE if the context is freed occurs otherwise FALSE.
  471. Notes:
  472. --*/
  473. {
  474. LONG result = 0;
  475. PIRP irp = NULL;
  476. PLIST_ENTRY listEntry;
  477. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = *AEContext;
  478. PRX_CONTEXT RxContext = AsyncEngineContext->RxContext;
  479. BOOLEAN AsyncOperation = FALSE, ReadWriteIrp = FALSE;
  480. FINALIZE_TRACKING_SETUP()
  481. PAGED_CODE();
  482. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  483. ("%ld: Entering UMRxFinalizeAsyncEngineContext\n",
  484. PsGetCurrentThreadId()));
  485. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  486. ("%ld: UMRxFinalizeAsyncEngineContext: "
  487. "AsyncEngineContext: %08lx, RxContext: %08lx\n",
  488. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  489. result = InterlockedDecrement( &(AsyncEngineContext->NodeReferenceCount) );
  490. if (result != 0) {
  491. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  492. ("%ld: UMRxFinalizeAsyncEngineContext: Returning w/o "
  493. "finalizing: (%d)\n", PsGetCurrentThreadId(), result));
  494. return FALSE;
  495. }
  496. FINALIZE_TRACKING(0x1);
  497. ASSERT(RxContext != NULL);
  498. //
  499. // If this is a Read or a Write IRP, we need to set ReadWriteIrp to TRUE.
  500. //
  501. if ( (RxContext->MajorFunction == IRP_MJ_READ) || (RxContext->MajorFunction == IRP_MJ_WRITE) ) {
  502. ReadWriteIrp = TRUE;
  503. }
  504. //
  505. // If the IRP was for Read or Write, we would not have added the context to
  506. // the global UMRxAsyncEngineContextList. For an explanation of why we do
  507. // not add AsyncEngineContexts that deal with read/write IRPs to this list,
  508. // look at the comment in UMRxCreateAsyncEngineContext where the context is
  509. // added to this list.
  510. //
  511. if (ReadWriteIrp == FALSE) {
  512. //
  513. // Remove the context from the global UMRxAsyncEngineContextList now that we
  514. // are going to free if after we do a few things. We need to synchronize
  515. // this operation.
  516. //
  517. ExAcquireResourceExclusiveLite(&(UMRxAsyncEngineContextListLock), TRUE);
  518. RemoveEntryList( &(AsyncEngineContext->ActiveContextsListEntry) );
  519. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  520. }
  521. while ( !IsListEmpty(&AsyncEngineContext->AllocationList) ) {
  522. PUMRX_SECONDARY_BUFFER buf = NULL;
  523. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  524. ("%ld: UMRxFinalizeAsyncEngineContext: Freeing the "
  525. "AllocationList of the AsyncEngineContext.\n",
  526. PsGetCurrentThreadId()));
  527. listEntry = AsyncEngineContext->AllocationList.Flink;
  528. buf = CONTAINING_RECORD(listEntry,
  529. UMRX_SECONDARY_BUFFER,
  530. ListEntry);
  531. UMRxFreeSecondaryBuffer(AsyncEngineContext, (PBYTE)&buf->Buffer);
  532. //
  533. // If it didn't remove this from the list, we're looping.
  534. //
  535. ASSERT(listEntry != AsyncEngineContext->AllocationList.Flink);
  536. }
  537. AsyncOperation = FlagOn(AsyncEngineContext->Flags, UMRX_ASYNCENG_CTX_FLAG_ASYNC_OPERATION);
  538. irp = AsyncEngineContext->CalldownIrp;
  539. //
  540. // If the CallDownIrp is not NULL, then we need to do the following.
  541. //
  542. if (irp != NULL) {
  543. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  544. ("%ld: UMRxFinalizeAsyncEngineContext: Freeing IRP = %08lx, MajorFn = %d\n",
  545. PsGetCurrentThreadId(), irp, RxContext->MajorFunction));
  546. if (irp->MdlAddress) {
  547. IoFreeMdl(irp->MdlAddress);
  548. }
  549. //
  550. // We are done with this irp, so free it.
  551. //
  552. IoFreeIrp(irp);
  553. FINALIZE_TRACKING(0x20);
  554. }
  555. //
  556. // If this was an Async Operation, then we need to complete the original
  557. // irp since we would have returned STATUS_PENDING back earlier. To do
  558. // this, we do one of two things.
  559. // 1. Call into the RxLowIoCompletion function if the LowIoCompletion
  560. // routine exists.
  561. // 2. Just complete the IRP if no such routine exists.
  562. // Also, we do this only if ShouldCallLowIoCompletion is set to TRUE since
  563. // some Async calls do not need this. Eg: CreateSrvCall is async but doesn't
  564. // need it. Ofcourse, if the operation was cancelled then there is no need
  565. // to call this since the routine that handles the cancelling would have
  566. // taken care of this.
  567. //
  568. if (AsyncOperation &&
  569. AsyncEngineContext->ShouldCallLowIoCompletion &&
  570. AsyncEngineContext->AsyncEngineContextState != UMRxAsyncEngineContextCancelled) {
  571. ASSERT(RxContext != NULL);
  572. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  573. ("%ld: UMRxFinalizeAsyncEngineContext: Async Operation\n",
  574. PsGetCurrentThreadId()));
  575. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  576. ("%ld: UMRxFinalizeAsyncEngineContext: Completing Irp = %08lx\n",
  577. PsGetCurrentThreadId(), RxContext->CurrentIrp));
  578. if (RxContext->LowIoContext.CompletionRoutine) {
  579. //
  580. // Set the status and information values in the RxContext. These are
  581. // the values returned by the underlying file system for the read
  582. // or the write operation that was issued to them.
  583. //
  584. RxContext->StoredStatus = AsyncEngineContext->Status;
  585. RxContext->InformationToReturn = AsyncEngineContext->Information;
  586. //
  587. // Finally, call RxLowIoCompletion.
  588. //
  589. RxLowIoCompletion(RxContext);
  590. } else {
  591. //
  592. // Complete the request by calling RxCompleteRequest.
  593. //
  594. RxContext->CurrentIrp->IoStatus.Status = AsyncEngineContext->Status;
  595. RxContext->CurrentIrp->IoStatus.Information = AsyncEngineContext->Information;
  596. RxCompleteRequest(RxContext, AsyncEngineContext->Status);
  597. }
  598. }
  599. //
  600. // We took a reference on the RxContext when we created the AsyncEngineContext.
  601. // Since we are done with the AsyncEngineContext, we need to remove it now.
  602. //
  603. RxDereferenceAndDeleteRxContext(AsyncEngineContext->RxContext);
  604. FINALIZE_TRACE("Ready to Discard Exchange");
  605. RxFreePool(AsyncEngineContext);
  606. //
  607. // Set the AsyncEngineContext pointer to NULL.
  608. //
  609. *AEContext = NULL;
  610. FINALIZE_TRACKING(0x3000);
  611. FINALIZE_TRACKING(0x40000);
  612. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  613. ("%ld: Leaving UMRxFinalizeAsyncEngineContext. Final State = "
  614. "%x\n", PsGetCurrentThreadId(), Tracking.finalstate));
  615. return(TRUE);
  616. }
  617. NTSTATUS
  618. UMRxAsyncEngineCalldownIrpCompletion(
  619. IN PDEVICE_OBJECT DeviceObject,
  620. IN PIRP CalldownIrp OPTIONAL,
  621. IN PVOID Context
  622. )
  623. /*++
  624. Routine Description:
  625. This routine is called when the calldownirp is completed.
  626. Arguments:
  627. DeviceObject - The device object in play.
  628. CalldownIrp -
  629. Context -
  630. Return Value:
  631. RXSTATUS - STATUS_MORE_PROCESSING_REQUIRED
  632. --*/
  633. {
  634. PRX_CONTEXT RxContext = (PRX_CONTEXT)Context;
  635. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext =
  636. (PUMRX_ASYNCENGINE_CONTEXT)RxContext->MRxContext[0];
  637. BOOLEAN AsyncOperation = FlagOn(AsyncEngineContext->Flags,
  638. UMRX_ASYNCENG_CTX_FLAG_ASYNC_OPERATION);
  639. //
  640. // This is not Pageable code.
  641. //
  642. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  643. ("%ld: Entering UMRxAsyncEngineCalldownIrpCompletion!!!!\n",
  644. PsGetCurrentThreadId()));
  645. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  646. ("%ld: UMRxAsyncEngineCalldownIrpCompletion: "
  647. "AsyncEngineContext: %08lx, RxContext: %08lx.\n",
  648. PsGetCurrentThreadId(), AsyncEngineContext, RxContext));
  649. UPDATE_HISTORY_WITH_STATUS('ff');
  650. UMRxAsyncEngAssertConsistentLinkage("UMRxCalldownCompletion: ", 0);
  651. //
  652. // If the CallDownIrp is not NULL, then this means that the underlying
  653. // filesystem has completed the read or the write IRP that we had given it
  654. // using the IoCallDriver call.
  655. //
  656. if (CalldownIrp != NULL) {
  657. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  658. ("%ld: UMRxAsyncEngineCalldownIrpCompletion: "
  659. "CallDownIrp = %08lx, MajorFunction = %d\n",
  660. PsGetCurrentThreadId(), CalldownIrp, RxContext->MajorFunction));
  661. AsyncEngineContext->Status = CalldownIrp->IoStatus.Status;
  662. AsyncEngineContext->Information = CalldownIrp->IoStatus.Information;
  663. }
  664. if (AsyncOperation) {
  665. NTSTATUS PostStatus = STATUS_SUCCESS;
  666. if (RxContext->pRelevantSrvOpen) {
  667. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  668. ("%ld: UMRxAsyncEngineCalldownIrpCompletion: "
  669. "ASync Resume. AsyncEngineContext = %08lx, RxContext "
  670. "= %08lx, FileName = %wZ\n",
  671. PsGetCurrentThreadId(), AsyncEngineContext, RxContext,
  672. RxContext->pRelevantSrvOpen->pAlreadyPrefixedName));
  673. }
  674. IF_DEBUG {
  675. //
  676. // Fill the workqueue structure with deadbeef. All the better to
  677. // diagnose a failed post.
  678. //
  679. ULONG i;
  680. for (i=0;
  681. i + sizeof(ULONG) - 1 < sizeof(AsyncEngineContext->WorkQueueItem);
  682. i += sizeof(ULONG)) {
  683. PBYTE BytePtr = ((PBYTE)&AsyncEngineContext->WorkQueueItem)+i;
  684. PULONG UlongPtr = (PULONG)BytePtr;
  685. *UlongPtr = 0xdeadbeef;
  686. }
  687. }
  688. PostStatus = RxPostToWorkerThread(RxContext->RxDeviceObject,
  689. CriticalWorkQueue,
  690. &(AsyncEngineContext->WorkQueueItem),
  691. UMRxResumeAsyncEngineContext,
  692. RxContext);
  693. ASSERT(PostStatus == STATUS_SUCCESS);
  694. } else {
  695. if (RxContext->pRelevantSrvOpen) {
  696. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  697. ("%ld: UMRxAsyncEngineCalldownIrpCompletion: "
  698. "Sync Resume. AsyncEngineContext = %08lx, RxContext "
  699. "= %08lx, FileName = %wZ\n",
  700. PsGetCurrentThreadId(), AsyncEngineContext, RxContext,
  701. RxContext->pRelevantSrvOpen->pAlreadyPrefixedName));
  702. }
  703. //
  704. // Signal the thread that is waiting after queuing the workitem on the
  705. // KQueue.
  706. //
  707. RxSignalSynchronousWaiter(RxContext);
  708. }
  709. return(STATUS_MORE_PROCESSING_REQUIRED);
  710. }
  711. NTSTATUS
  712. UMRxPostOperation(
  713. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  714. IN OUT PVOID PostedOpContext,
  715. IN PUMRX_POSTABLE_OPERATION Operation
  716. )
  717. /*++
  718. Routine Description:
  719. Arguments:
  720. RxContext - The RDBSS context.
  721. Return Value:
  722. RXSTATUS - The return status for the operation
  723. --*/
  724. {
  725. NTSTATUS Status,PostStatus;
  726. PAGED_CODE();
  727. ASSERT_ASYNCENG_CONTEXT(AsyncEngineContext);
  728. KeInitializeEvent(&RxContext->SyncEvent,
  729. NotificationEvent,
  730. FALSE);
  731. AsyncEngineContext->PostedOpContext = PostedOpContext;
  732. IF_DEBUG {
  733. //
  734. // Fill the workqueue structure with deadbeef. All the better to
  735. // diagnose a failed post
  736. //
  737. ULONG i;
  738. for (i = 0;
  739. i + sizeof(ULONG) - 1 < sizeof(AsyncEngineContext->WorkQueueItem);
  740. i += sizeof(ULONG)) {
  741. PBYTE BytePtr = ((PBYTE)&AsyncEngineContext->WorkQueueItem)+i;
  742. PULONG UlongPtr = (PULONG)BytePtr;
  743. *UlongPtr = 0xdeadbeef;
  744. }
  745. }
  746. PostStatus = RxPostToWorkerThread(RxContext->RxDeviceObject,
  747. DelayedWorkQueue,
  748. &AsyncEngineContext->WorkQueueItem,
  749. Operation,
  750. AsyncEngineContext);
  751. ASSERT(PostStatus == STATUS_SUCCESS);
  752. RxWaitSync(RxContext);
  753. Status = AsyncEngineContext->PostedOpStatus;
  754. return(Status);
  755. }
  756. NTSTATUS
  757. UMRxAcquireMidAndFormatHeader(
  758. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE,
  759. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  760. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader
  761. )
  762. /*++
  763. Routine Description:
  764. This routine gets a mid and formats the header. It waits until it can get a
  765. MID if all the MIDs are currently passed out.
  766. Arguments:
  767. RxContext - The RDBSS context.
  768. AsyncEngineContext - The Reflector's AsynEngine's context.
  769. UMRefDeviceObject - The UMRef device object.
  770. WorkItemHeader - The work item header buffer.
  771. Return Value:
  772. STATUS_SUCCESS. Later could be STATUS_CANCELLED.
  773. --*/
  774. {
  775. NTSTATUS NtStatus = STATUS_SUCCESS;
  776. PUMRX_WORKITEM_HEADER_PRIVATE PrivateWorkItemHeader = NULL;
  777. ULONG WorkItemHeaderLength = 0;
  778. PAGED_CODE();
  779. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  780. ("%ld: Entering UMRxAcquireMidAndFormatHeader!!!!\n",
  781. PsGetCurrentThreadId()));
  782. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  783. ("%ld: UMRxAcquireMidAndFormatHeader: WorkItem = %08lx, "
  784. "AsyncEngineContext = %08lx, RxContext = %08lx.\n",
  785. PsGetCurrentThreadId(), WorkItemHeader, AsyncEngineContext,
  786. RxContext));
  787. PrivateWorkItemHeader = (PUMRX_WORKITEM_HEADER_PRIVATE)WorkItemHeader;
  788. //
  789. // We are going to zero the entire WorkItemHeader below. Before we do that
  790. // we need to store the value of "WorkItemHeader->WorkItemLength" on the
  791. // stack. After we zero this structure, we copy this value back.
  792. //
  793. WorkItemHeaderLength = WorkItemHeader->WorkItemLength;
  794. RtlZeroMemory(WorkItemHeader, sizeof(UMRX_USERMODE_WORKITEM_HEADER));
  795. WorkItemHeader->WorkItemLength = WorkItemHeaderLength;
  796. ExAcquireFastMutex(&UMRefDeviceObject->MidManagementMutex);
  797. //
  798. // Taken away as we disassociate the mid.
  799. //
  800. InterlockedIncrement( &(AsyncEngineContext->NodeReferenceCount) );
  801. if (IsListEmpty(&UMRefDeviceObject->WaitingForMidListhead)) {
  802. NtStatus = RxAssociateContextWithMid(UMRefDeviceObject->MidAtlas,
  803. AsyncEngineContext,
  804. &AsyncEngineContext->UserMode.CallUpMid);
  805. if (NtStatus != STATUS_SUCCESS) {
  806. UMRxDbgTrace(UMRX_TRACE_ERROR,
  807. ("%ld: ERROR: UMRxAcquireMidAndFormatHeader/"
  808. "RxAssociateContextWithMid: NtStatus = %08lx\n",
  809. PsGetCurrentThreadId(), NtStatus));
  810. }
  811. } else {
  812. NtStatus = STATUS_UNSUCCESSFUL;
  813. UMRxDbgTrace(UMRX_TRACE_ERROR,
  814. ("%ld: ERROR: UMRxAcquireMidAndFormatHeader. "
  815. "WaitingForMidList is not empty.\n", PsGetCurrentThreadId()));
  816. }
  817. if (NtStatus == STATUS_SUCCESS) {
  818. ExReleaseFastMutex(&UMRefDeviceObject->MidManagementMutex);
  819. } else {
  820. KeInitializeEvent(&AsyncEngineContext->UserMode.WaitForMidEvent,
  821. NotificationEvent,
  822. FALSE);
  823. InsertTailList(&UMRefDeviceObject->WaitingForMidListhead,
  824. &AsyncEngineContext->UserMode.WorkQueueLinks);
  825. ExReleaseFastMutex(&UMRefDeviceObject->MidManagementMutex);
  826. KeWaitForSingleObject(&AsyncEngineContext->UserMode.WaitForMidEvent,
  827. Executive,
  828. UserMode,
  829. FALSE,
  830. NULL);
  831. NtStatus = STATUS_SUCCESS;
  832. }
  833. PrivateWorkItemHeader->AsyncEngineContext = AsyncEngineContext;
  834. AsyncEngineContext->UserMode.CallUpSerialNumber
  835. = PrivateWorkItemHeader->SerialNumber
  836. = InterlockedIncrement(&UMRefDeviceObject->NextSerialNumber);
  837. PrivateWorkItemHeader->Mid = AsyncEngineContext->UserMode.CallUpMid;
  838. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  839. ("%ld: Leaving UMRxAcquireMidAndFormatHeader with NtStatus = "
  840. "%08lx\n", PsGetCurrentThreadId(), NtStatus));
  841. return(NtStatus);
  842. }
  843. NTSTATUS
  844. UMRxPrepareUserModeRequestBuffer(
  845. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  846. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  847. OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  848. IN ULONG WorkItemHeaderLength,
  849. OUT PIO_STATUS_BLOCK IoStatus
  850. )
  851. /*++
  852. Routine Description:
  853. This routine dispatches to a usermode guy using the info in the asyncengine
  854. context. The workerirp is represented by the captureheader.
  855. Arguments:
  856. AsyncEngineContext - The context associated with the request that is being
  857. sent to the usermode.
  858. UMRefDeviceObject - The device object in play.
  859. WorkItemHeader - The workitem buffer.
  860. WorkItemHeaderLength - Length of the WorkItemHeader buffer.
  861. IoStatus - The reults of the assignment.
  862. Return Value:
  863. STATUS_SUCCESS if the thread should be released with the IoStatus returned
  864. otherwise, don't release the thread.
  865. --*/
  866. {
  867. NTSTATUS NtStatus = STATUS_SUCCESS;
  868. PRX_CONTEXT RxContext;
  869. PUMRX_ASYNCENG_USERMODE_FORMAT_ROUTINE FormatRoutine;
  870. BOOL MidAcquired = FALSE, lockAcquired = FALSE, OperationCancelled = TRUE;
  871. PAGED_CODE();
  872. RxContext = AsyncEngineContext->RxContext;
  873. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  874. ("%ld: Entering UMRxPrepareUserModeRequestBuffer!!!!\n",
  875. PsGetCurrentThreadId()));
  876. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  877. ("%ld: UMRxPrepareUserModeRequestBuffer: "
  878. "WorkItemHeader = %08lx, AsyncEngineContext = %08lx, "
  879. "RxContext = %08lx\n", PsGetCurrentThreadId(), WorkItemHeader,
  880. AsyncEngineContext, RxContext));
  881. ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT);
  882. ASSERT(AsyncEngineContext->RxContext == RxContext);
  883. //
  884. // We need to make sure that the request has not been cancelled since it
  885. // was put on the KQueue. If it has been cancelled, then we don't need to
  886. // go to the usermode and can do the finalization right away. If it has not
  887. // been cancelled, the we keep the global ContextListlock, complete the
  888. // format routine and then release the lock.
  889. //
  890. ExAcquireResourceExclusiveLite(&(UMRxAsyncEngineContextListLock), TRUE);
  891. lockAcquired = TRUE;
  892. if (AsyncEngineContext->AsyncEngineContextState == UMRxAsyncEngineContextInUserMode) {
  893. //
  894. // Need checks that things are the right size.
  895. //
  896. if (UMRefDeviceObject != (PUMRX_DEVICE_OBJECT)(RxContext->RxDeviceObject)) {
  897. NtStatus = STATUS_INVALID_PARAMETER;
  898. UMRxDbgTrace(UMRX_TRACE_ERROR,
  899. ("%ld: ERROR: UMRxPrepareUserModeRequestBuffer: "
  900. "Invalid DevObj.\n", PsGetCurrentThreadId()));
  901. goto EXIT_THE_FUNCTION;
  902. }
  903. FormatRoutine = AsyncEngineContext->UserMode.FormatRoutine;
  904. NtStatus = UMRxAcquireMidAndFormatHeader(UMRX_ASYNCENGINE_ARGUMENTS,
  905. UMRefDeviceObject,
  906. WorkItemHeader);
  907. if (NtStatus != STATUS_SUCCESS) {
  908. UMRxDbgTrace(UMRX_TRACE_ERROR,
  909. ("%ld: ERROR: UMRxPrepareUserModeRequestBuffer/"
  910. "UMRxAcquireMidAndFormatHeader: Error Val = %08lx.\n",
  911. PsGetCurrentThreadId(), NtStatus));
  912. goto EXIT_THE_FUNCTION;
  913. }
  914. MidAcquired = TRUE;
  915. if (FormatRoutine != NULL) {
  916. NtStatus = FormatRoutine(UMRX_ASYNCENGINE_ARGUMENTS,
  917. WorkItemHeader,
  918. WorkItemHeaderLength,
  919. &IoStatus->Information);
  920. if (NtStatus != STATUS_SUCCESS) {
  921. UMRxDbgTrace(UMRX_TRACE_ERROR,
  922. ("%ld: ERROR: UMRxPrepareUserModeRequestBuffer/"
  923. "FormatRoutine: Error Val = %08lx.\n",
  924. PsGetCurrentThreadId(), NtStatus));
  925. goto EXIT_THE_FUNCTION;
  926. }
  927. }
  928. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  929. lockAcquired = FALSE;
  930. } else {
  931. BOOLEAN ReturnVal;
  932. NtStatus = STATUS_CANCELLED;
  933. ASSERT(AsyncEngineContext->AsyncEngineContextState == UMRxAsyncEngineContextCancelled);
  934. UMRxDbgTrace(UMRX_TRACE_ERROR,
  935. ("%ld: ERROR: UMRxPrepareUserModeRequestBuffer: OperationCancelled\n",
  936. PsGetCurrentThreadId()));
  937. OperationCancelled = TRUE;
  938. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  939. lockAcquired = FALSE;
  940. //
  941. // If this is an AsyncOperation, we need to Finalize the context now.
  942. // There MUST be 3 references on it. One was taken when the context was
  943. // created. The second was taken in the UMRxSubmitAsyncEngUserModeRequest
  944. // routine just before the context was placed on the KQueue. The third
  945. // one was taken in UMRxEnqueueUserModeCallUp to account for the cancel
  946. // logic. Read the comment in UMRxEnqueueUserModeCallUp for the reason.
  947. //
  948. if (AsyncEngineContext->AsyncOperation) {
  949. ReturnVal = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  950. ASSERT(!ReturnVal);
  951. ReturnVal = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  952. ASSERT(!ReturnVal);
  953. ReturnVal = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  954. ASSERT(ReturnVal == TRUE);
  955. } else {
  956. //
  957. // If this is a synchronous operation, then there must be just one
  958. // reference on it which was taken in UMRxEnqueueUserModeCallUp. The
  959. // other two would have been taken out by the sync thread handling
  960. // the operation when it was cancelled.
  961. //
  962. ReturnVal = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  963. }
  964. }
  965. EXIT_THE_FUNCTION:
  966. IoStatus->Status = NtStatus;
  967. //
  968. // If some error occured while preparing the user mode buffer, then we
  969. // need to complete the request, returning the error and not go to the user
  970. // mode.
  971. //
  972. if (NtStatus != STATUS_SUCCESS) {
  973. NTSTATUS LocalStatus;
  974. //
  975. // If we failed after acquiring the MID, we need to release it.
  976. //
  977. if (MidAcquired) {
  978. LocalStatus = UMRxVerifyHeader(UMRefDeviceObject,
  979. WorkItemHeader,
  980. REASSIGN_MID,
  981. &(AsyncEngineContext));
  982. if (LocalStatus != STATUS_SUCCESS) {
  983. UMRxDbgTrace(UMRX_TRACE_ERROR,
  984. ("%ld: ERROR: UMRxPrepareUserModeRequestBuffer/UMRxVerifyHeader:"
  985. " NtStatus = %08lx.\n", PsGetCurrentThreadId(), LocalStatus));
  986. goto EXIT_THE_FUNCTION;
  987. }
  988. }
  989. //
  990. // If the operation was cancelled, we did not even Format the request,
  991. // so there is no point in calling UMRxCompleteUserModeErroneousRequest.
  992. // If this was an Async request, we would have already finalized the
  993. // AsyncEngineContext above.
  994. //
  995. if (!OperationCancelled) {
  996. AsyncEngineContext->Status = NtStatus;
  997. LocalStatus = UMRxCompleteUserModeErroneousRequest(AsyncEngineContext,
  998. UMRefDeviceObject,
  999. WorkItemHeader,
  1000. WorkItemHeaderLength);
  1001. }
  1002. }
  1003. //
  1004. // If we have the global context lock acquired, we need to release it now.
  1005. // UMRxCompleteUserModeErroneousRequest has to be called (if needed) before
  1006. // the lock is freed. This is very important.
  1007. //
  1008. if (lockAcquired) {
  1009. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  1010. lockAcquired = FALSE;
  1011. }
  1012. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1013. ("%ld: Leaving UMRxPrepareUserModeRequestBuffer with "
  1014. "NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1015. return(NtStatus);
  1016. }
  1017. NTSTATUS
  1018. UMRxCompleteUserModeErroneousRequest(
  1019. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  1020. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  1021. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1022. IN ULONG WorkItemHeaderLength
  1023. )
  1024. /*++
  1025. Routine Description:
  1026. This routine is called to complete a request that failed while the user
  1027. buffer was being formatted.
  1028. IMPORTANT!!!
  1029. This can ONLY be called at one place, in the failure case of
  1030. UMRxPrepareUserModeRequestBuffer. It cannot be used as a general routine.
  1031. Its very important to keep this in mind.
  1032. Arguments:
  1033. AsyncEngineContext - The context associated with the request that is being
  1034. sent to the usermode.
  1035. UMRefDeviceObject - The device object in play.
  1036. WorkItemHeader - The workitem buffer.
  1037. WorkItemHeaderLength - Length of the WorkItemHeader buffer.
  1038. Return Value:
  1039. STATUS_SUCCESS or the approprate error status value.
  1040. --*/
  1041. {
  1042. NTSTATUS NtStatus = STATUS_SUCCESS;
  1043. PRX_CONTEXT RxContext;
  1044. PUMRX_ASYNCENG_USERMODE_PRECOMPLETION_ROUTINE PreCompletionRoutine;
  1045. BOOL Call = FALSE;
  1046. PAGED_CODE();
  1047. RxContext = AsyncEngineContext->RxContext;
  1048. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1049. ("%ld: Entering UMRxCompleteUserModeErroneousRequest!!!!\n",
  1050. PsGetCurrentThreadId()));
  1051. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1052. ("%ld: UMRxCompleteUserModeErroneousRequest: "
  1053. "WorkItemHeader = %08lx, AsyncEngineContext = %08lx, "
  1054. "RxContext = %08lx\n", PsGetCurrentThreadId(), WorkItemHeader,
  1055. AsyncEngineContext, RxContext));
  1056. PreCompletionRoutine = AsyncEngineContext->UserMode.PrecompletionRoutine;
  1057. if (PreCompletionRoutine != NULL) {
  1058. Call = PreCompletionRoutine(UMRX_ASYNCENGINE_ARGUMENTS,
  1059. WorkItemHeader,
  1060. WorkItemHeaderLength,
  1061. FALSE);
  1062. }
  1063. //
  1064. // We now need to remove the reference taken to handle the cancel logic
  1065. // of the timer thread correctly in UMRxEnqueueUserModeCallUp.
  1066. //
  1067. UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  1068. //
  1069. // The PreCompletion routine can finalize the AsyncEngineContext. In such
  1070. // a situation, we are done. All that the routine below does is to signal
  1071. // the thread that is waiting for this request to complete.
  1072. //
  1073. if (Call) {
  1074. UMRxAsyncEngineCalldownIrpCompletion(&UMRefDeviceObject->DeviceObject,
  1075. NULL,
  1076. RxContext);
  1077. }
  1078. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1079. ("%ld: Leaving UMRxCompleteUserModeErroneousRequest with NtStatus = "
  1080. "%08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1081. return(NtStatus);
  1082. }
  1083. NTSTATUS
  1084. UMRxVerifyHeader(
  1085. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  1086. IN PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1087. IN ULONG ReassignmentCmd,
  1088. OUT PUMRX_ASYNCENGINE_CONTEXT *capturedAsyncEngineContext
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. This routine makes sure that the header passed in is valid. That is, that
  1093. it really refers to the operation encoded. if it does, then it reasigns or
  1094. releases the MID as appropriate.
  1095. Arguments:
  1096. UMRefDeviceObject - The reflctor's device object.
  1097. WorkItemHeader - The work item buffer
  1098. ReassignmentCmd -
  1099. capturedAsyncEngineContext - The context associated with the WorkItemHeader.
  1100. Return Value:
  1101. STATUS_SUCCESS if the header is good
  1102. STATUS_INVALID_PARAMETER otherwise
  1103. --*/
  1104. {
  1105. NTSTATUS NtStatus = STATUS_SUCCESS;
  1106. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = NULL;
  1107. PRX_CONTEXT RxContext = NULL;
  1108. UMRX_USERMODE_WORKITEM_HEADER capturedHeader;
  1109. PUMRX_WORKITEM_HEADER_PRIVATE PrivateWorkItemHeader = NULL;
  1110. PAGED_CODE();
  1111. PrivateWorkItemHeader = (PUMRX_WORKITEM_HEADER_PRIVATE)(&capturedHeader);
  1112. capturedHeader = *WorkItemHeader;
  1113. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1114. ("%ld: Entering UMRxVerifyHeader!!!!\n",
  1115. PsGetCurrentThreadId()));
  1116. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1117. ("%ld: UMRxVerifyHeader: UMRefDeviceObject = %08lx, "
  1118. "WorkItemHeader = %08lx.\n", PsGetCurrentThreadId(),
  1119. UMRefDeviceObject, WorkItemHeader));
  1120. ExAcquireFastMutex( &(UMRefDeviceObject->MidManagementMutex) );
  1121. AsyncEngineContext = RxMapMidToContext(UMRefDeviceObject->MidAtlas,
  1122. PrivateWorkItemHeader->Mid);
  1123. if ( (AsyncEngineContext == NULL) ||
  1124. (AsyncEngineContext != PrivateWorkItemHeader->AsyncEngineContext) ||
  1125. (AsyncEngineContext->UserMode.CallUpMid != PrivateWorkItemHeader->Mid) ||
  1126. (AsyncEngineContext->UserMode.CallUpSerialNumber != PrivateWorkItemHeader->SerialNumber) ||
  1127. (&UMRefDeviceObject->RxDeviceObject != AsyncEngineContext->RxContext->RxDeviceObject) ) {
  1128. //
  1129. // This is a bad packet. Just release and get out.
  1130. //
  1131. ExReleaseFastMutex(&UMRefDeviceObject->MidManagementMutex);
  1132. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1133. ("%ld: ERROR: UMRxVerifyHeader/RxMapMidToContext.\n",
  1134. PsGetCurrentThreadId()));
  1135. NtStatus = STATUS_INVALID_PARAMETER;
  1136. } else {
  1137. BOOLEAN Finalized;
  1138. RxContext = AsyncEngineContext->RxContext;
  1139. UMRxAsyncEngAssertConsistentLinkage("UMRxVerifyHeaderAndReAssignMid: ", 0);
  1140. *capturedAsyncEngineContext = AsyncEngineContext;
  1141. if (ReassignmentCmd == DONT_REASSIGN_MID) {
  1142. ExReleaseFastMutex(&UMRefDeviceObject->MidManagementMutex);
  1143. } else {
  1144. //
  1145. // Remove the reference I put before I went off.
  1146. //
  1147. Finalized = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  1148. ASSERT(!Finalized);
  1149. //
  1150. // Now give up the MID. If there is someone waiting then give it to
  1151. // him. Otherwise, just give it back
  1152. //
  1153. if (IsListEmpty(&UMRefDeviceObject->WaitingForMidListhead)) {
  1154. PVOID DummyContext;
  1155. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1156. ("%ld: UMRxVerifyHeader: Giving up mid.\n",
  1157. PsGetCurrentThreadId()));
  1158. RxMapAndDissociateMidFromContext(UMRefDeviceObject->MidAtlas,
  1159. PrivateWorkItemHeader->Mid,
  1160. &DummyContext);
  1161. ExReleaseFastMutex(&UMRefDeviceObject->MidManagementMutex);
  1162. } else {
  1163. PLIST_ENTRY ThisEntry = RemoveHeadList(&UMRefDeviceObject->WaitingForMidListhead);
  1164. AsyncEngineContext = CONTAINING_RECORD(ThisEntry,
  1165. UMRX_ASYNCENGINE_CONTEXT,
  1166. UserMode.WorkQueueLinks);
  1167. UMRxAsyncEngAssertConsistentLinkage("UMRxVerifyHeaderAndReAssignMid: ", 0);
  1168. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1169. ("%ld: UMRxVerifyHeader: Reassigning MID: %08lx.\n",
  1170. PsGetCurrentThreadId(), PrivateWorkItemHeader->Mid));
  1171. RxReassociateMid(UMRefDeviceObject->MidAtlas,
  1172. PrivateWorkItemHeader->Mid,
  1173. AsyncEngineContext);
  1174. ExReleaseFastMutex(&UMRefDeviceObject->MidManagementMutex);
  1175. AsyncEngineContext->UserMode.CallUpMid = PrivateWorkItemHeader->Mid;
  1176. KeSetEvent(&AsyncEngineContext->UserMode.WaitForMidEvent,
  1177. IO_NO_INCREMENT,
  1178. FALSE);
  1179. }
  1180. }
  1181. }
  1182. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1183. ("%ld: Leaving UMRxVerifyHeader with NtStatus = %08lx.\n",
  1184. PsGetCurrentThreadId(), NtStatus));
  1185. return(NtStatus);
  1186. }
  1187. NTSTATUS
  1188. UMRxCompleteUserModeRequest(
  1189. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  1190. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader,
  1191. IN ULONG WorkItemHeaderLength,
  1192. OUT PIO_STATUS_BLOCK IoStatus
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. This routine dispatches to a usermode guy using the info in the asyncengine
  1197. context. The workerirp is represented by the captureheader.
  1198. Arguments:
  1199. UMRefDeviceObject - The device object in play.
  1200. WorkItemHeader - The workitem buffer.
  1201. WorkItemHeaderLength - Length of the WorkItemHeader buffer.
  1202. IoStatus - The results of the assignment.
  1203. Return Value:
  1204. STATUS_SUCCESS if the thread should be released with the IoStatus returned,
  1205. otherwise don't release the thread.
  1206. --*/
  1207. {
  1208. NTSTATUS NtStatus = STATUS_SUCCESS;
  1209. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = NULL;
  1210. PRX_CONTEXT RxContext = NULL;
  1211. PUMRX_ASYNCENG_USERMODE_PRECOMPLETION_ROUTINE PreCompletionRoutine = NULL;
  1212. BOOL Call = FALSE, OperationCancelled = FALSE;
  1213. PAGED_CODE();
  1214. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1215. ("%ld: Entering UMRxCompleteUserModeRequest!!!!\n",
  1216. PsGetCurrentThreadId()));
  1217. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1218. ("%ld: UMRxCompleteUserModeRequest: UMRefDeviceObject: %08lx,"
  1219. " WorkItemHeader = %08lx.\n", PsGetCurrentThreadId(),
  1220. UMRefDeviceObject, WorkItemHeader));
  1221. NtStatus = UMRxVerifyHeader(UMRefDeviceObject,
  1222. WorkItemHeader,
  1223. REASSIGN_MID,
  1224. &AsyncEngineContext);
  1225. if (NtStatus != STATUS_SUCCESS) {
  1226. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1227. ("%ld: ERROR: UMRxCompleteUserModeRequest/UMRxVerifyHeader:"
  1228. " NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1229. goto EXIT_THE_FUNCTION;
  1230. }
  1231. //
  1232. // If the request has not been cancelled, then we change the state of the
  1233. // context to UMRxAsyncEngineContextBackFromUserMode. If it has been cancelled,
  1234. // we only need to do the cleanup.
  1235. //
  1236. ExAcquireResourceExclusiveLite(&(UMRxAsyncEngineContextListLock), TRUE);
  1237. if (AsyncEngineContext->AsyncEngineContextState == UMRxAsyncEngineContextInUserMode) {
  1238. AsyncEngineContext->AsyncEngineContextState = UMRxAsyncEngineContextBackFromUserMode;
  1239. } else {
  1240. ASSERT(AsyncEngineContext->AsyncEngineContextState == UMRxAsyncEngineContextCancelled);
  1241. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1242. ("%ld: ERROR: UMRxCompleteUserModeRequest: UMRxAsyncEngineContextCancelled. AsyncEngineContext = %08lx\n",
  1243. PsGetCurrentThreadId(), AsyncEngineContext));
  1244. OperationCancelled = TRUE;
  1245. }
  1246. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  1247. RxContext = AsyncEngineContext->RxContext;
  1248. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1249. ("%ld: UMRxCompleteUserModeRequest: AsyncEngineContext = %08lx"
  1250. ", RxContext = %08lx\n", PsGetCurrentThreadId(),
  1251. AsyncEngineContext, RxContext));
  1252. PreCompletionRoutine = AsyncEngineContext->UserMode.PrecompletionRoutine;
  1253. AsyncEngineContext->Status = WorkItemHeader->Status;
  1254. if (PreCompletionRoutine != NULL) {
  1255. Call = PreCompletionRoutine(UMRX_ASYNCENGINE_ARGUMENTS,
  1256. WorkItemHeader,
  1257. WorkItemHeaderLength,
  1258. OperationCancelled);
  1259. }
  1260. //
  1261. // We now need to remove the reference taken to handle the cancel logic
  1262. // of the timer thread correctly in UMRxEnqueueUserModeCallUp.
  1263. //
  1264. UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  1265. //
  1266. // The PreCompletion routine can finalize the AsyncEngineContext. In such
  1267. // a situation, we are done. All that the routine below does is to signal
  1268. // the thread that is waiting for this request to complete. So, if the
  1269. // operation has been cancelled, we do not need to call
  1270. // UMRxAsyncEngineCalldownIrpCompletion.
  1271. //
  1272. if (Call && !OperationCancelled) {
  1273. UMRxAsyncEngineCalldownIrpCompletion(&UMRefDeviceObject->DeviceObject,
  1274. NULL,
  1275. RxContext);
  1276. }
  1277. EXIT_THE_FUNCTION:
  1278. IoStatus->Status = NtStatus;
  1279. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1280. ("%ld: Leaving UMRxCompleteUserModeRequest with NtStatus = "
  1281. "%08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1282. return(NtStatus);
  1283. }
  1284. NTSTATUS
  1285. UMRxEnqueueUserModeCallUp(
  1286. UMRX_ASYNCENGINE_ARGUMENT_SIGNATURE
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. This routine enqueues a work request and returns STATUS_PENDING.
  1291. Arguments:
  1292. RxContext - The RDBSS context.
  1293. AsyncEngineContext - The reflector's context.
  1294. Return Value:
  1295. STATUS_PENDING.
  1296. --*/
  1297. {
  1298. NTSTATUS NtStatus = STATUS_PENDING;
  1299. PUMRX_DEVICE_OBJECT UMRefDeviceObject = NULL;
  1300. PAGED_CODE();
  1301. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)(RxContext->RxDeviceObject);
  1302. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1303. ("%ld: Entering UMRxEnqueueUserModeCallUp!!!!\n",
  1304. PsGetCurrentThreadId()));
  1305. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1306. ("%ld: UMRxEnqueueUserModeCallUp: AsyncEngineContext: %08lx, "
  1307. "RxContext: %08lx.\n", PsGetCurrentThreadId(),
  1308. AsyncEngineContext, RxContext));
  1309. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1310. ("%ld: UMRxEnqueueUserModeCallUp: Try to Queue up the request.\n",
  1311. PsGetCurrentThreadId()));
  1312. //
  1313. // Before placing an item on the queue, we check to see if the user mode
  1314. // DAV process is still alive and accepting requests. If its not, we return
  1315. // an error code.
  1316. //
  1317. ExAcquireResourceExclusiveLite(&(UMRefDeviceObject->Q.QueueLock), TRUE);
  1318. if (!UMRefDeviceObject->Q.WorkersAccepted) {
  1319. NtStatus = STATUS_REDIRECTOR_NOT_STARTED;
  1320. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1321. ("%ld: UMRxEnqueueUserModeCallUp: Requests no longer"
  1322. "accepted by the usermode process. NtStatus = %08lx.\n",
  1323. PsGetCurrentThreadId(), NtStatus));
  1324. ExReleaseResourceLite(&(UMRefDeviceObject->Q.QueueLock));
  1325. return NtStatus;
  1326. }
  1327. ExReleaseResourceLite(&(UMRefDeviceObject->Q.QueueLock));
  1328. //
  1329. // We need to make sure that the request has not been cancelled. If it has,
  1330. // then we just return STATUS_CANCELLED.
  1331. //
  1332. ExAcquireResourceExclusiveLite(&(UMRxAsyncEngineContextListLock), TRUE);
  1333. if (AsyncEngineContext->AsyncEngineContextState == UMRxAsyncEngineContextCancelled) {
  1334. NtStatus = STATUS_CANCELLED;
  1335. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1336. ("%ld: UMRxEnqueueUserModeCallUp: NtStatus = %08lx.\n",
  1337. PsGetCurrentThreadId(), NtStatus));
  1338. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  1339. return NtStatus;
  1340. }
  1341. //
  1342. // We now change the state of the context to reflect that is has been sent
  1343. // to the usermode.
  1344. //
  1345. AsyncEngineContext->AsyncEngineContextState = UMRxAsyncEngineContextInUserMode;
  1346. ExReleaseResourceLite(&(UMRxAsyncEngineContextListLock));
  1347. //
  1348. // At this stage the reference count of the AsyncEngineContext should be 2.
  1349. // We need to take another reference to make sure that the context stays
  1350. // alive in case this request was a synchronous one and got cancelled by
  1351. // the Timeout thread. If the request is synchronous and is cancelled by
  1352. // the timeout thread, then the thread will remove both the references that
  1353. // we have taken so far. This reference is taken out in before the request
  1354. // is sent to the Format routine or the Precomplete routine depending on
  1355. // when (and if) the request was cancelled.
  1356. //
  1357. InterlockedIncrement( &(AsyncEngineContext->NodeReferenceCount) );
  1358. //
  1359. // Increment the number of workitems.
  1360. //
  1361. InterlockedIncrement(&UMRefDeviceObject->Q.NumberOfWorkItems);
  1362. KeInsertQueue(&UMRefDeviceObject->Q.Queue,
  1363. &AsyncEngineContext->UserMode.WorkQueueLinks);
  1364. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1365. ("%ld: Leaving UMRxEnqueueUserModeCallUp with NtStatus = "
  1366. "%08lx.\n", PsGetCurrentThreadId(), NtStatus));
  1367. return(NtStatus);
  1368. }
  1369. VOID
  1370. UMRxAssignWork(
  1371. IN PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  1372. IN OUT PUMRX_USERMODE_WORKITEM_HEADER InputWorkItem,
  1373. IN ULONG InputWorkItemLength,
  1374. IN OUT PUMRX_USERMODE_WORKITEM_HEADER OutputWorkItem,
  1375. IN ULONG OutputWorkItemLength,
  1376. OUT PIO_STATUS_BLOCK IoStatus
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. This routine assigns work to a worker thread. If no work is available then
  1381. the thread is captured until work shows up.
  1382. Arguments:
  1383. UMRefDeviceObject - The deviceobject that is in play.
  1384. IoControlCode - The control code of the operation.
  1385. InputWorkItem - The Input buffer that came down from the user mode.
  1386. InputWorkItemLength - Length of the InputBuffer.
  1387. OutputWorkItem - The Output buffer that came down from the user mode.
  1388. OutputWorkItemLength - Length of the OutputBuffer.
  1389. IoStatus - The results of the assignment.
  1390. Return Value:
  1391. None.
  1392. --*/
  1393. {
  1394. NTSTATUS NtStatus;
  1395. PETHREAD CurrentThread = PsGetCurrentThread();
  1396. ULONG i;
  1397. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext;
  1398. PLIST_ENTRY pListEntry;
  1399. ULONG NumberOfWorkerThreads;
  1400. PAGED_CODE();
  1401. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1402. ("%ld: Entering UMRxAssignWork!!!!\n",
  1403. PsGetCurrentThreadId()));
  1404. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1405. ("%ld: UMRxAssignWork: UMRefDevObj: %08lx\n",
  1406. PsGetCurrentThreadId(), UMRefDeviceObject));
  1407. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1408. ("%ld: UMRxAssignWork: CurrentThread: %08lx\n",
  1409. PsGetCurrentThreadId(), CurrentThread));
  1410. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1411. ("%ld: UMRxAssignWork: InputWorkItem: %08lx\n",
  1412. PsGetCurrentThreadId(), InputWorkItem));
  1413. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1414. ("%ld: UMRxAssignWork: OutputWorkItem: %08lx\n",
  1415. PsGetCurrentThreadId(), OutputWorkItem));
  1416. IoStatus->Information = 0;
  1417. IoStatus->Status = STATUS_CANNOT_IMPERSONATE;
  1418. if (!UMRefDeviceObject->Q.WorkersAccepted) {
  1419. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1420. ("%ld: ERROR: UMRxAssignWork: No Workers accepted\n",
  1421. PsGetCurrentThreadId()));
  1422. return;
  1423. }
  1424. if (OutputWorkItem != NULL) {
  1425. if (OutputWorkItemLength < sizeof(UMRX_USERMODE_WORKITEM_HEADER)) {
  1426. IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
  1427. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1428. ("%ld: ERROR: UMRxAssignWork: Output request buffer is too small\n",
  1429. PsGetCurrentThreadId()));
  1430. return;
  1431. }
  1432. }
  1433. if (InputWorkItem != NULL) {
  1434. if (InputWorkItemLength < sizeof(UMRX_USERMODE_WORKITEM_HEADER)) {
  1435. IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
  1436. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1437. ("%ld: ERROR: UMRxAssignWork: Input request buffer is too small\n",
  1438. PsGetCurrentThreadId()));
  1439. return;
  1440. }
  1441. }
  1442. //
  1443. // We need to check if this IOCTL carries a response to an earlier request
  1444. // with it. The response is present if the InputWorkItem is != NULL. If it
  1445. // does carry a response, we need to process that response.
  1446. //
  1447. if (InputWorkItem != NULL) {
  1448. //
  1449. // If this thread was impersonating a client, we need to revert back
  1450. // and clear the flag.
  1451. //
  1452. if( (InputWorkItem->Flags & UMRX_WORKITEM_IMPERSONATING) ) {
  1453. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1454. ("%ld: UMRxAssignWork: InputWorkItem had Impersonating"
  1455. " flag set.\n", PsGetCurrentThreadId()));
  1456. UMRxRevertClient();
  1457. InputWorkItem->Flags &= ~UMRX_WORKITEM_IMPERSONATING;
  1458. }
  1459. //
  1460. // We need to disable APCs on this thread now.
  1461. //
  1462. FsRtlEnterFileSystem();
  1463. //
  1464. // Complete the request for which the response has been received.
  1465. //
  1466. NtStatus = UMRxCompleteUserModeRequest(UMRefDeviceObject,
  1467. InputWorkItem,
  1468. InputWorkItemLength,
  1469. IoStatus);
  1470. if (NtStatus != STATUS_SUCCESS) {
  1471. IoStatus->Status = NtStatus;
  1472. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1473. ("%ld: ERROR: UMRxAssignWork/UMRxCompleteUserModeRequest:"
  1474. " NtStatus = %08lx\n", PsGetCurrentThreadId(), NtStatus));
  1475. FsRtlExitFileSystem();
  1476. return;
  1477. }
  1478. FsRtlExitFileSystem();
  1479. } else {
  1480. ASSERT(OutputWorkItem != NULL);
  1481. //
  1482. // If this thread was impersonating a client, we need to revert back
  1483. // and clear the flag.
  1484. //
  1485. if( (OutputWorkItem->Flags & UMRX_WORKITEM_IMPERSONATING) ) {
  1486. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1487. ("%ld: UMRxAssignWork: OutputWorkItem had Impersonating"
  1488. " flag set.\n", PsGetCurrentThreadId()));
  1489. UMRxRevertClient();
  1490. OutputWorkItem->Flags &= ~UMRX_WORKITEM_IMPERSONATING;
  1491. }
  1492. }
  1493. //
  1494. // If this thread only carried a response, we should return now.
  1495. //
  1496. if (OutputWorkItem == NULL) {
  1497. IoStatus->Status = NtStatus;
  1498. return;
  1499. }
  1500. //
  1501. // Now, increment the number of threads.
  1502. //
  1503. InterlockedIncrement( &(UMRefDeviceObject->Q.NumberOfWorkerThreads) );
  1504. for (i = 1; ;i++) {
  1505. pListEntry = KeRemoveQueue(&UMRefDeviceObject->Q.Queue, UserMode, NULL); // &UMRefDeviceObject->Q.TimeOut);
  1506. if ((ULONG_PTR)pListEntry == STATUS_TIMEOUT) {
  1507. ASSERT(!"STATUS_TIMEOUT Happened");
  1508. if ((i % 5) == 0) {
  1509. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1510. ("%ld: UMRxAssignWork/KeRemoveQueue: RepostCnt = "
  1511. "%d\n", PsGetCurrentThreadId(), i));
  1512. }
  1513. continue;
  1514. }
  1515. if ((ULONG_PTR)pListEntry == STATUS_USER_APC) {
  1516. IoStatus->Status = STATUS_USER_APC;
  1517. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1518. ("%ld: UMRxAssignWork/KeRemoveQueue: UsrApc.\n",
  1519. PsGetCurrentThreadId()));
  1520. break;
  1521. }
  1522. //
  1523. // Check to see if the entry is a Poison one. If it is, it means that
  1524. // the usermode process wants to cleanup the worker threads.
  1525. //
  1526. if (pListEntry == &UMRefDeviceObject->Q.PoisonEntry) {
  1527. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1528. ("%ld: UMRxAssignWork/KeRemoveQueue: Poison Entry.\n",
  1529. PsGetCurrentThreadId()));
  1530. KeInsertQueue(&UMRefDeviceObject->Q.Queue, pListEntry);
  1531. goto FINALLY;
  1532. }
  1533. //
  1534. // We need to disable APCs on this thread now.
  1535. //
  1536. FsRtlEnterFileSystem();
  1537. //
  1538. // Decrement the number of workitems.
  1539. //
  1540. InterlockedDecrement(&UMRefDeviceObject->Q.NumberOfWorkItems);
  1541. AsyncEngineContext = CONTAINING_RECORD(pListEntry,
  1542. UMRX_ASYNCENGINE_CONTEXT,
  1543. UserMode.WorkQueueLinks);
  1544. ASSERT(NodeType(AsyncEngineContext) == UMRX_NTC_ASYNCENGINE_CONTEXT);
  1545. NtStatus = UMRxPrepareUserModeRequestBuffer(AsyncEngineContext,
  1546. UMRefDeviceObject,
  1547. OutputWorkItem,
  1548. OutputWorkItemLength,
  1549. IoStatus);
  1550. if (NtStatus != STATUS_SUCCESS) {
  1551. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1552. ("%ld: ERROR: UMRxAssignWork/"
  1553. "UMRxPrepareUserModeRequestBuffer: NtStatus = %08lx\n",
  1554. PsGetCurrentThreadId(), NtStatus));
  1555. FsRtlExitFileSystem();
  1556. continue;
  1557. }
  1558. ASSERT(((IoStatus->Status == STATUS_SUCCESS) ||
  1559. (IoStatus->Status == STATUS_INVALID_PARAMETER)));
  1560. FsRtlExitFileSystem();
  1561. break;
  1562. }
  1563. FINALLY:
  1564. //
  1565. // Now, decrement the number of threads.
  1566. //
  1567. NumberOfWorkerThreads =
  1568. InterlockedDecrement(&UMRefDeviceObject->Q.NumberOfWorkerThreads);
  1569. //
  1570. // Check to see if the threads are being cleaned up by the user mode
  1571. // process. When this happens, the WorkersAccepted field of the device
  1572. // object is set to FALSE. If the threads are being cleaned up and if I was
  1573. // the last thread waiting on the KQUEUE, its my responsibility to set the
  1574. // RunDownEvent.
  1575. //
  1576. if ((NumberOfWorkerThreads == 0) && !UMRefDeviceObject->Q.WorkersAccepted){
  1577. KeSetEvent(&UMRefDeviceObject->Q.RunDownEvent,
  1578. IO_NO_INCREMENT,
  1579. FALSE);
  1580. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1581. ("%ld: UMRxAssignWork: Last Thread.\n",
  1582. PsGetCurrentThreadId()));
  1583. }
  1584. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1585. ("%ld: Leaving UMRxAssignWork with IoStatus->Status = %08lx\n",
  1586. PsGetCurrentThreadId(), IoStatus->Status));
  1587. return;
  1588. }
  1589. VOID
  1590. UMRxReleaseCapturedThreads(
  1591. IN OUT PUMRX_DEVICE_OBJECT UMRefDeviceObject
  1592. )
  1593. /*++
  1594. Routine Description:
  1595. Arguments:
  1596. UMRefDeviceObject - Device object whose threads are to be released.
  1597. Return Value:
  1598. none.
  1599. --*/
  1600. {
  1601. LONG NumberWorkerThreads;
  1602. PAGED_CODE();
  1603. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1604. ("%ld: Entering UMRxReleaseCapturedThreads!!!!\n",
  1605. PsGetCurrentThreadId()));
  1606. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1607. ("%ld: UMRxReleaseCapturedThreads: UMRefDeviceObject: %08lx.\n",
  1608. PsGetCurrentThreadId(), UMRefDeviceObject));
  1609. //
  1610. // We need to disable APCs on this thread now.
  1611. //
  1612. FsRtlEnterFileSystem();
  1613. //
  1614. // The WorkersAccepted field is initialized to TRUE when the device object
  1615. // gets created and it set to FALSE here. If more than one thread tries to
  1616. // release the threads, only the first one should do the job. The rest
  1617. // should just return. This check is performed below before the thread is
  1618. // allowed to proceed with the release of ser mode worker threads.
  1619. //
  1620. ExAcquireResourceExclusiveLite(&(UMRefDeviceObject->Q.QueueLock), TRUE);
  1621. if (!UMRefDeviceObject->Q.WorkersAccepted) {
  1622. ExReleaseResourceLite(&(UMRefDeviceObject->Q.QueueLock));
  1623. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1624. ("%ld: Worker threads have already returned.\n",
  1625. PsGetCurrentThreadId()));
  1626. FsRtlExitFileSystem();
  1627. return;
  1628. }
  1629. UMRefDeviceObject->Q.WorkersAccepted = FALSE;
  1630. ExReleaseResourceLite(&(UMRefDeviceObject->Q.QueueLock));
  1631. //
  1632. // Insert the poison entry. When a worker thread sees this, it realizes that
  1633. // the usermode process intends to cleanup the worker threads.
  1634. //
  1635. KeInsertQueue(&UMRefDeviceObject->Q.Queue,
  1636. &UMRefDeviceObject->Q.PoisonEntry);
  1637. NumberWorkerThreads =
  1638. InterlockedCompareExchange(&UMRefDeviceObject->Q.NumberOfWorkerThreads,
  1639. 0,
  1640. 0);
  1641. if (NumberWorkerThreads != 0) {
  1642. //
  1643. // The RunDownEvent is set by the last thread just before it returns to
  1644. // the usermode.
  1645. //
  1646. KeWaitForSingleObject(&UMRefDeviceObject->Q.RunDownEvent,
  1647. Executive,
  1648. UserMode,
  1649. FALSE,
  1650. NULL);
  1651. }
  1652. FsRtlExitFileSystem();
  1653. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1654. ("%ld: Leaving UMRxReleaseCapturedThreads.\n",
  1655. PsGetCurrentThreadId()));
  1656. return;
  1657. }
  1658. PBYTE
  1659. UMRxAllocateSecondaryBuffer(
  1660. IN OUT PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  1661. SIZE_T Length
  1662. )
  1663. /*++
  1664. Routine Description:
  1665. This routine allocates memory for the secondary buffer of the
  1666. AsyncEngineContext.
  1667. Arguments:
  1668. AsyncEngineContext - The reflector's context.
  1669. Length - The length in bytes of the buffer to be allocated.
  1670. Return Value:
  1671. Pointer to the buffer or NULL.
  1672. --*/
  1673. {
  1674. PBYTE rv = NULL;
  1675. PRX_CONTEXT RxContext = AsyncEngineContext->RxContext;
  1676. PUMRX_DEVICE_OBJECT UMRefDeviceObject;
  1677. PUMRX_SECONDARY_BUFFER buf = NULL;
  1678. PUMRX_SHARED_HEAP sharedHeap;
  1679. PLIST_ENTRY listEntry;
  1680. PAGED_CODE();
  1681. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1682. ("%ld: Entering UMRxAllocateSecondaryBuffer.\n",
  1683. PsGetCurrentThreadId()));
  1684. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1685. ("%ld: UMRxAllocateSecondaryBuffer: AsyncEngineContext: %08lx,"
  1686. " Bytes Asked: %d.\n",
  1687. PsGetCurrentThreadId(), AsyncEngineContext, Length));
  1688. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)(RxContext->RxDeviceObject);
  1689. if (Length > UMRefDeviceObject->NewHeapSize) {
  1690. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1691. ("%ld: ERROR: UMRxAllocateSecondaryBuffer: Length > NewHeapSize.\n",
  1692. PsGetCurrentThreadId()));
  1693. return NULL;
  1694. }
  1695. ExAcquireResourceExclusiveLite(&UMRefDeviceObject->HeapLock, TRUE);
  1696. listEntry = UMRefDeviceObject->SharedHeapList.Flink;
  1697. //
  1698. // We search the list of heaps for just the added safety of not letting
  1699. // the user mode corrupt the pointer and us going off corrupting random
  1700. // memory. Only the local shared heap should have the chance at corruption.
  1701. //
  1702. while (listEntry != &UMRefDeviceObject->SharedHeapList && buf == NULL) {
  1703. sharedHeap = (PUMRX_SHARED_HEAP) CONTAINING_RECORD(listEntry,
  1704. UMRX_SHARED_HEAP,
  1705. HeapListEntry);
  1706. listEntry = listEntry->Flink;
  1707. if (sharedHeap->HeapFull) {
  1708. continue;
  1709. }
  1710. buf = (PUMRX_SECONDARY_BUFFER)RtlAllocateHeap(
  1711. sharedHeap->Heap,
  1712. HEAP_NO_SERIALIZE,
  1713. Length + sizeof(UMRX_SECONDARY_BUFFER));
  1714. if (buf != NULL) {
  1715. break;
  1716. }
  1717. }
  1718. if (buf == NULL) {
  1719. //
  1720. // We won't get into the situation where the heap is too small for
  1721. // the object we're trying to allocate even though we just allocated
  1722. // a fresh heap.
  1723. //
  1724. SIZE_T heapSize = max(UMRefDeviceObject->NewHeapSize, 2 * Length);
  1725. sharedHeap = UMRxAddSharedHeap(UMRefDeviceObject, heapSize);
  1726. if (sharedHeap != NULL) {
  1727. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1728. ("%ld: UMRxAllocateSecondaryBuffer: sharedHeap: %08lx.\n",
  1729. PsGetCurrentThreadId(), sharedHeap));
  1730. buf = (PUMRX_SECONDARY_BUFFER)
  1731. RtlAllocateHeap(
  1732. sharedHeap->Heap,
  1733. HEAP_NO_SERIALIZE,
  1734. Length + sizeof(UMRX_SECONDARY_BUFFER));
  1735. }
  1736. }
  1737. if (buf != NULL) {
  1738. //
  1739. // We insert into the list while holding the HeapLock so that we
  1740. // don't have to worry about the list getting corrupted.
  1741. //
  1742. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1743. ("%ld: UMRxAllocateSecondaryBuffer: buf: %08lx.\n",
  1744. PsGetCurrentThreadId(), buf));
  1745. sharedHeap->HeapAllocationCount++;
  1746. buf->Signature = UMRX_SECONDARY_BUFFER_SIGNATURE;
  1747. buf->AllocationSize = Length;
  1748. buf->SourceSharedHeap = sharedHeap;
  1749. InsertHeadList(&AsyncEngineContext->AllocationList, &buf->ListEntry);
  1750. rv = (PCHAR) &buf->Buffer[0];
  1751. }
  1752. ExReleaseResourceLite(&UMRefDeviceObject->HeapLock);
  1753. if (rv == NULL) {
  1754. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1755. ("%ld: ERROR: UMRxAllocateSecondaryBuffer allocation failed"
  1756. ". Size = %08lx\n", PsGetCurrentThreadId(), Length));
  1757. return(NULL);
  1758. }
  1759. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1760. ("%ld: Leaving UMRxAllocateSecondaryBuffer. rv = %08lx.\n",
  1761. PsGetCurrentThreadId(), rv));
  1762. return rv;
  1763. }
  1764. NTSTATUS
  1765. UMRxFreeSecondaryBuffer(
  1766. IN OUT PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext,
  1767. PBYTE BufferToFree
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. This routine frees up the memory allocated for the secondary buffer of the
  1772. AsyncEngineContext.
  1773. Arguments:
  1774. AsyncEngineContext - The reflector's context.
  1775. Return Value:
  1776. none.
  1777. --*/
  1778. {
  1779. PRX_CONTEXT RxContext = AsyncEngineContext->RxContext;
  1780. PUMRX_DEVICE_OBJECT UMRefDeviceObject;
  1781. PUMRX_SECONDARY_BUFFER buf;
  1782. PUMRX_SHARED_HEAP sharedHeap;
  1783. PLIST_ENTRY listEntry;
  1784. BOOLEAN checkVal = FALSE;
  1785. PAGED_CODE();
  1786. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1787. ("%ld: Entering UMRxFreeSecondaryBuffer.\n",
  1788. PsGetCurrentThreadId()));
  1789. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1790. ("%ld: UMRxFreeSecondaryBuffer: AsyncEngineContext: %08lx,"
  1791. " BufferToFree: %08lx.\n",
  1792. PsGetCurrentThreadId(), AsyncEngineContext, BufferToFree));
  1793. UMRefDeviceObject = (PUMRX_DEVICE_OBJECT)(RxContext->RxDeviceObject);
  1794. ASSERT(BufferToFree != NULL);
  1795. buf = CONTAINING_RECORD(BufferToFree, UMRX_SECONDARY_BUFFER, Buffer);
  1796. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1797. ("%ld: UMRxFreeSecondaryBuffer: buf: %08lx.\n",
  1798. PsGetCurrentThreadId(), buf));
  1799. ASSERT(buf->SourceSharedHeap);
  1800. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1801. ("%ld: UMRxFreeSecondaryBuffer: buf->SourceSharedHeap: %08lx.\n",
  1802. PsGetCurrentThreadId(), buf->SourceSharedHeap));
  1803. ExAcquireResourceExclusiveLite(&UMRefDeviceObject->HeapLock, TRUE);
  1804. listEntry = UMRefDeviceObject->SharedHeapList.Flink;
  1805. //
  1806. // We search the list of heaps for just the added safety of not letting
  1807. // the user mode corrupt the pointer and us going off corrupting random
  1808. // memory. only the local shared heap should have the chance at corruption.
  1809. //
  1810. while (listEntry != &UMRefDeviceObject->SharedHeapList) {
  1811. sharedHeap = (PUMRX_SHARED_HEAP) CONTAINING_RECORD(listEntry,
  1812. UMRX_SHARED_HEAP,
  1813. HeapListEntry);
  1814. ASSERT(sharedHeap);
  1815. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1816. ("%ld: UMRxFreeSecondaryBuffer: sharedHeap: %08lx.\n",
  1817. PsGetCurrentThreadId(), sharedHeap));
  1818. if (sharedHeap == buf->SourceSharedHeap) {
  1819. break;
  1820. }
  1821. listEntry = listEntry->Flink;
  1822. }
  1823. ASSERT(listEntry != &UMRefDeviceObject->SharedHeapList);
  1824. if (listEntry == &UMRefDeviceObject->SharedHeapList) {
  1825. //
  1826. // Ouch. This block isn't in any that we know about.
  1827. //
  1828. ExReleaseResourceLite(&UMRefDeviceObject->HeapLock);
  1829. return STATUS_INVALID_PARAMETER;
  1830. }
  1831. RemoveEntryList(&buf->ListEntry);
  1832. sharedHeap->HeapAllocationCount--;
  1833. checkVal = RtlFreeHeap(sharedHeap->Heap, 0, buf);
  1834. if (!checkVal) {
  1835. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1836. ("%ld: ERROR: UMRxFreeSecondaryBuffer/RtlFreeHeap.\n",
  1837. PsGetCurrentThreadId()));
  1838. }
  1839. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1840. ("%ld: UMRxFreeSecondaryBuffer: sharedHeap->Heap = %08lx.\n",
  1841. PsGetCurrentThreadId(), sharedHeap->Heap));
  1842. sharedHeap->HeapFull = FALSE;
  1843. if (sharedHeap->HeapAllocationCount == 0) {
  1844. //
  1845. // If this was the last allocation in this heap, let's see if there's
  1846. // any other empty heaps. If there are, we'll free one of them.
  1847. // This prevents us from holding the max number of heaps during
  1848. // varying loads.
  1849. //
  1850. PUMRX_SHARED_HEAP secondarySharedHeap;
  1851. listEntry = UMRefDeviceObject->SharedHeapList.Flink;
  1852. while (listEntry != &UMRefDeviceObject->SharedHeapList) {
  1853. secondarySharedHeap = (PUMRX_SHARED_HEAP)
  1854. CONTAINING_RECORD(listEntry,
  1855. UMRX_SHARED_HEAP,
  1856. HeapListEntry);
  1857. if ( (secondarySharedHeap->HeapAllocationCount == 0) &&
  1858. (secondarySharedHeap != sharedHeap) ) {
  1859. break;
  1860. }
  1861. listEntry = listEntry->Flink;
  1862. }
  1863. if (listEntry != &UMRefDeviceObject->SharedHeapList) {
  1864. PVOID HeapHandle;
  1865. RemoveEntryList(listEntry);
  1866. HeapHandle = RtlDestroyHeap(secondarySharedHeap->Heap);
  1867. if (HeapHandle != NULL) {
  1868. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1869. ("%ld: ERROR: UMRxFreeSecondaryBuffer/RtlDestroyHeap.\n",
  1870. PsGetCurrentThreadId()));
  1871. }
  1872. ZwFreeVirtualMemory(NtCurrentProcess(),
  1873. &secondarySharedHeap->VirtualMemoryBuffer,
  1874. &secondarySharedHeap->VirtualMemoryLength,
  1875. MEM_RELEASE);
  1876. RxFreePool(secondarySharedHeap);
  1877. }
  1878. }
  1879. ExReleaseResourceLite(&UMRefDeviceObject->HeapLock);
  1880. return STATUS_SUCCESS;
  1881. }
  1882. PUMRX_SHARED_HEAP
  1883. UMRxAddSharedHeap(
  1884. PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  1885. SIZE_T HeapSize
  1886. )
  1887. /*++
  1888. Routine Description:
  1889. This routine allocates the shared heap which is used to pass stuff onto the
  1890. user mode. It allocated virtual memory, creates a heap and returns a pointer
  1891. to it. If the functions fails a NULL is returned.
  1892. Arguments:
  1893. UMRefDeviceObject - The Reflector's device object.
  1894. HeapSize - The size of the heap being allocated.
  1895. Return Value:
  1896. Pointer to the creatted heap or NULL.
  1897. --*/
  1898. {
  1899. PBYTE buff = NULL;
  1900. NTSTATUS err;
  1901. PUMRX_SHARED_HEAP sharedHeap = NULL;
  1902. PAGED_CODE();
  1903. //
  1904. // We assume the device object's heap lock is held coming in here.
  1905. //
  1906. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1907. ("%ld: Entering UMRxAddSharedHeap.\n", PsGetCurrentThreadId()));
  1908. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  1909. ("%ld: UMRxAddSharedHeap: UMRefDeviceObject: %08lx, "
  1910. "HeapSize: %d.\n",
  1911. PsGetCurrentThreadId(), UMRefDeviceObject, HeapSize));
  1912. //
  1913. // We allocate the heap structure in paged pool rather than in virtual
  1914. // memory so that there is zero possiblity that user mode code could
  1915. // corrupt our list of heaps. It can still corrupt a heap, but that's
  1916. // something we'll have to live with for now.
  1917. //
  1918. sharedHeap = RxAllocatePoolWithTag(PagedPool,
  1919. sizeof(UMRX_SHARED_HEAP),
  1920. UMRX_SHAREDHEAP_POOLTAG);
  1921. if (sharedHeap == NULL) {
  1922. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1923. ("%ld: ERROR: UMRxAddSharedHeap/RxAllocatePoolWithTag: "
  1924. "Couldn't get the sharedHeap structure!\n",
  1925. PsGetCurrentThreadId()));
  1926. return NULL;
  1927. }
  1928. sharedHeap->VirtualMemoryLength = HeapSize;
  1929. sharedHeap->VirtualMemoryBuffer = NULL;
  1930. sharedHeap->Heap = NULL;
  1931. sharedHeap->HeapAllocationCount = 0;
  1932. sharedHeap->HeapFull = FALSE;
  1933. err = ZwAllocateVirtualMemory(NtCurrentProcess(),
  1934. (PVOID *) &buff,
  1935. 0,
  1936. &sharedHeap->VirtualMemoryLength,
  1937. MEM_COMMIT,
  1938. PAGE_READWRITE);
  1939. if (NT_SUCCESS(err)) {
  1940. SIZE_T ReserveSize = HeapSize;
  1941. sharedHeap->Heap = RtlCreateHeap(HEAP_NO_SERIALIZE,
  1942. (PVOID) buff,
  1943. ReserveSize,
  1944. PAGE_SIZE,
  1945. NULL,
  1946. 0);
  1947. if (sharedHeap->Heap == NULL) {
  1948. err = STATUS_NO_MEMORY;
  1949. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1950. ("%ld: ERROR: UMRxAddSharedHeap/RtlCreateHeap: "
  1951. "NtStatus = %08lx\n", PsGetCurrentThreadId(), err));
  1952. ZwFreeVirtualMemory(NtCurrentProcess(),
  1953. (PVOID *) &buff,
  1954. &HeapSize,
  1955. MEM_RELEASE);
  1956. RxFreePool(sharedHeap);
  1957. sharedHeap = NULL;
  1958. } else {
  1959. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1960. ("%ld: UMRxAddSharedHeap: sharedHeap->Heap = %08lx.\n",
  1961. PsGetCurrentThreadId(), sharedHeap->Heap));
  1962. sharedHeap->VirtualMemoryBuffer = buff;
  1963. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  1964. ("%ld: UMRxAddSharedHeap: "
  1965. "&UMRefDeviceObject->SharedHeapList: %08lx.\n",
  1966. PsGetCurrentThreadId(),
  1967. &UMRefDeviceObject->SharedHeapList));
  1968. InsertHeadList(&UMRefDeviceObject->SharedHeapList,
  1969. &sharedHeap->HeapListEntry);
  1970. }
  1971. } else {
  1972. UMRxDbgTrace(UMRX_TRACE_ERROR,
  1973. ("%ld: ERROR: UMRxAddSharedHeap/ZwAllocateVirtualMemory:"
  1974. " NtStatus = %08lx.\n", PsGetCurrentThreadId(), err));
  1975. RxFreePool(sharedHeap);
  1976. sharedHeap = NULL;
  1977. }
  1978. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  1979. ("%ld: Leaving UMRxAddSharedHeap.\n", PsGetCurrentThreadId()));
  1980. return sharedHeap;
  1981. }
  1982. #if DBG
  1983. #define UMRX_DEBUG_KEY L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\MRxDAV\\Parameters"
  1984. #define UMRX_DEBUG_VALUE L"UMRxDebugFlag"
  1985. #endif
  1986. NTSTATUS
  1987. UMRxInitializeDeviceObject(
  1988. OUT PUMRX_DEVICE_OBJECT UMRefDeviceObject,
  1989. IN USHORT MaxNumberMids,
  1990. IN USHORT InitialMids,
  1991. IN SIZE_T HeapSize
  1992. )
  1993. /*++
  1994. Routine Description:
  1995. This initializes the UMRX_DEVICE_OBJECT structure. The shared heap
  1996. is created for shared memory between kernel and user.
  1997. Arguments:
  1998. UMRefDeviceObject - The reflector's device object to be initialized.
  1999. MaxNumberMids - Maximum number of mids to be used.
  2000. InitialMids - Initial number of mids allocated.
  2001. Return Value:
  2002. NTSTATUS
  2003. --*/
  2004. {
  2005. NTSTATUS err = STATUS_SUCCESS;
  2006. PRX_MID_ATLAS MidAtlas = NULL;
  2007. PAGED_CODE();
  2008. //
  2009. // This is the first reflector routine called by the Mini-Redir and so is
  2010. // the place where the UMRxDebugVector should be initialized.
  2011. //
  2012. #if DBG
  2013. UMRxReadDWORDFromTheRegistry(UMRX_DEBUG_KEY, UMRX_DEBUG_VALUE, &(UMRxDebugVector));
  2014. #endif
  2015. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  2016. ("%ld: Entering UMRxInitializeDeviceObject!!!!\n",
  2017. PsGetCurrentThreadId()));
  2018. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  2019. ("%ld: UMRxInitializeDeviceObject: UMRefDeviceObject: %08lx\n",
  2020. PsGetCurrentThreadId(), UMRefDeviceObject));
  2021. //
  2022. // MidAtlas.
  2023. //
  2024. MidAtlas = RxCreateMidAtlas(MaxNumberMids, InitialMids);
  2025. if (MidAtlas == NULL) {
  2026. err = STATUS_INSUFFICIENT_RESOURCES;
  2027. UMRxDbgTrace(UMRX_TRACE_ERROR,
  2028. ("%ld: ERROR: UMRxInitializeDeviceObject/RxCreateMidAtlas:"
  2029. " NtStatus = %08lx.\n", PsGetCurrentThreadId(), err));
  2030. return(err);
  2031. }
  2032. UMRefDeviceObject->MidAtlas = MidAtlas;
  2033. InitializeListHead(&UMRefDeviceObject->WaitingForMidListhead);
  2034. ExInitializeFastMutex(&UMRefDeviceObject->MidManagementMutex);
  2035. //
  2036. // Initialize the global AsyncEngineContext list and the mutex that is used
  2037. // to synchronize access to it.
  2038. //
  2039. InitializeListHead( &(UMRxAsyncEngineContextList) );
  2040. ExInitializeResourceLite( &(UMRxAsyncEngineContextListLock) );
  2041. //
  2042. // Heap.
  2043. //
  2044. UMRefDeviceObject->NewHeapSize = HeapSize;
  2045. InitializeListHead(&UMRefDeviceObject->SharedHeapList);
  2046. ExInitializeResourceLite(&UMRefDeviceObject->HeapLock);
  2047. //
  2048. // KQUEUE.
  2049. //
  2050. KeInitializeQueue(&UMRefDeviceObject->Q.Queue, 0);
  2051. ExInitializeResourceLite(&(UMRefDeviceObject->Q.QueueLock));
  2052. UMRefDeviceObject->Q.TimeOut.QuadPart = -10 * TICKS_PER_SECOND;
  2053. KeInitializeEvent(&UMRefDeviceObject->Q.RunDownEvent,
  2054. NotificationEvent,
  2055. FALSE);
  2056. UMRefDeviceObject->Q.NumberOfWorkerThreads = 0;
  2057. UMRefDeviceObject->Q.NumberOfWorkItems = 0;
  2058. UMRefDeviceObject->Q.WorkersAccepted = TRUE;
  2059. //
  2060. // This specifies the alignment requirement for unbuffered writes. Assuming
  2061. // that the sector size on disks is 512 bytes, the size of the writes should
  2062. // be a multiple of the 512 (SectorSize).
  2063. //
  2064. UMRefDeviceObject->SectorSize = 512;
  2065. RxMakeLateDeviceAvailable(&UMRefDeviceObject->RxDeviceObject);
  2066. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  2067. ("%ld: Leaving UMRxInitializeDeviceObject with NtStatus = "
  2068. "%08lx.\n", PsGetCurrentThreadId(), STATUS_SUCCESS));
  2069. return STATUS_SUCCESS;
  2070. }
  2071. NTSTATUS
  2072. UMRxCleanUpDeviceObject(
  2073. PUMRX_DEVICE_OBJECT UMRefDeviceObject
  2074. )
  2075. /*++
  2076. Routine Description:
  2077. This destorys the instance data for a UMReflector device object.
  2078. Arguments:
  2079. UMRefDeviceObject - The reflector's device object to be destroyed.
  2080. Return Value:
  2081. NTSTATUS
  2082. --*/
  2083. {
  2084. PLIST_ENTRY pFirstListEntry, pNextListEntry;
  2085. BOOLEAN FoundPoisoner = FALSE;
  2086. PAGED_CODE();
  2087. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  2088. ("%ld: Entering UMRxCleanUpDeviceObject!!!!\n",
  2089. PsGetCurrentThreadId()));
  2090. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  2091. ("%ld: UMRxCleanUpDeviceObject: UMRefDeviceObject: %08lx.\n",
  2092. PsGetCurrentThreadId(), UMRefDeviceObject));
  2093. //
  2094. // Delete the resource that was created to synchronize access to the
  2095. // AsyncEngineContext list.
  2096. //
  2097. ExDeleteResourceLite( &(UMRxAsyncEngineContextListLock) );
  2098. //
  2099. // Delete the resource that was created to synchronize access to the heap.
  2100. //
  2101. ExDeleteResourceLite(&UMRefDeviceObject->HeapLock);
  2102. //
  2103. // If we created a MidAtlas structure, we need to destroy it now.
  2104. //
  2105. if (UMRefDeviceObject->MidAtlas != NULL) {
  2106. RxDestroyMidAtlas(UMRefDeviceObject->MidAtlas, NULL);
  2107. }
  2108. //
  2109. // Run down the KQUEUE to make sure that they are no outstanding queued
  2110. // requests. There shouldn't be any.
  2111. //
  2112. pFirstListEntry = KeRundownQueue(&UMRefDeviceObject->Q.Queue);
  2113. if (pFirstListEntry != NULL) {
  2114. pNextListEntry = pFirstListEntry;
  2115. do {
  2116. PLIST_ENTRY ThisEntry = pNextListEntry;
  2117. pNextListEntry = pNextListEntry->Flink;
  2118. if (ThisEntry != &UMRefDeviceObject->Q.PoisonEntry) {
  2119. UMRxDbgTrace(UMRX_TRACE_ERROR,
  2120. ("%ld: ERROR: UMRxCleanUpDeviceObject: Non Poisoner In The KQueue: %08lx\n",
  2121. PsGetCurrentThreadId(), ThisEntry));
  2122. } else {
  2123. FoundPoisoner = TRUE;
  2124. }
  2125. } while (pNextListEntry != pFirstListEntry);
  2126. }
  2127. ExDeleteResourceLite(&(UMRefDeviceObject->Q.QueueLock));
  2128. if (!FoundPoisoner) {
  2129. UMRxDbgTrace(UMRX_TRACE_ERROR,
  2130. ("%ld: ERROR: UMRxCleanUpDeviceObject: No Poisoner in queue.\n",
  2131. PsGetCurrentThreadId()));
  2132. }
  2133. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  2134. ("%ld: Leaving UMRxCleanUpDeviceObject.\n",
  2135. PsGetCurrentThreadId()));
  2136. return STATUS_SUCCESS;
  2137. }
  2138. NTSTATUS
  2139. UMRxImpersonateClient(
  2140. IN PSECURITY_CLIENT_CONTEXT SecurityClientContext,
  2141. IN OUT PUMRX_USERMODE_WORKITEM_HEADER WorkItemHeader
  2142. )
  2143. /*++
  2144. Routine Description:
  2145. This routine impersonates a worker thread to get the credentials of the
  2146. client of the I/O operation.
  2147. Arguments:
  2148. SecurityClientContext - The security context of the client used in the
  2149. impersonation call.
  2150. WorkItemHeader - The workitem associated with this request. If the
  2151. impersonation succeeds, the UMRX_WORKITEM_IMPERSONATING
  2152. flag is set in the workitem.
  2153. Return Value:
  2154. An NTSTATUS value.
  2155. --*/
  2156. {
  2157. NTSTATUS NtStatus = STATUS_SUCCESS;
  2158. PAGED_CODE();
  2159. ASSERT(SecurityClientContext != NULL);
  2160. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  2161. ("%ld: Entering UMRxImpersonateClient!!!!\n",
  2162. PsGetCurrentThreadId()));
  2163. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  2164. ("%ld: UMRxImpersonateClient: SecurityClientContext: %08lx.\n",
  2165. PsGetCurrentThreadId(), SecurityClientContext));
  2166. NtStatus = SeImpersonateClientEx(SecurityClientContext, NULL);
  2167. if (!NT_SUCCESS(NtStatus)) {
  2168. UMRxDbgTrace(UMRX_TRACE_ERROR,
  2169. ("%ld: ERROR: UMRxImpersonateClient/SeImpersonateClientEx"
  2170. ". NtStatus = %08lx.\n", PsGetCurrentThreadId(), NtStatus));
  2171. } else {
  2172. //
  2173. // Set the impersonating flag in the workitem.
  2174. //
  2175. UMRxDbgTrace(UMRX_TRACE_DETAIL,
  2176. ("%ld: UMRxImpersonateClient: Setting the Impersonation"
  2177. " Flag.\n", PsGetCurrentThreadId()));
  2178. WorkItemHeader->Flags |= UMRX_WORKITEM_IMPERSONATING;
  2179. }
  2180. return NtStatus;
  2181. }
  2182. NTSTATUS
  2183. UMRxAsyncEngOuterWrapper(
  2184. IN PRX_CONTEXT RxContext,
  2185. IN ULONG AdditionalBytes,
  2186. IN PUMRX_ASYNCENG_CONTEXT_FORMAT_ROUTINE ContextFormatRoutine,
  2187. USHORT FormatContext,
  2188. IN PUMRX_ASYNCENG_CONTINUE_ROUTINE Continuation,
  2189. IN PSZ RoutineName
  2190. )
  2191. /*++
  2192. Routine Description:
  2193. This routine is common to guys who use the async context engine. It has the
  2194. responsibility for getting a context, initing, starting and finalizing it,
  2195. but the internal guts of the procesing is via the continuation routine
  2196. that is passed in.
  2197. Arguments:
  2198. RxContext - The RDBSS context.
  2199. AdditionalBytes - The Additional bytes to be allocated for the context.
  2200. Some Mini-Redirs might need them.
  2201. ContextFormatRoutine - The routine that formats the Mini-Redirs portion of
  2202. the context. This may be NULL if the Mini-Redir does
  2203. not need any extra context fields.
  2204. FormatContext - The context passed to the ContextFormatRoutine. Its
  2205. not relvant if the ContextFormatRoutine is NULL.
  2206. Continuation - The Continuation routine which handles this I/O Request once
  2207. AsynEngineContext has been setup.
  2208. RotuineName - The name of the entry routine that called this function.
  2209. Return Value:
  2210. RXSTATUS - The return status for the operation
  2211. --*/
  2212. {
  2213. NTSTATUS NtStatus = STATUS_SUCCESS;
  2214. PUMRX_ASYNCENGINE_CONTEXT AsyncEngineContext = NULL;
  2215. ULONG SizeToAllocateInBytes;
  2216. PAGED_CODE();
  2217. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  2218. ("%ld: Entering UMRxAsyncEngOuterWrapper!!!!\n",
  2219. PsGetCurrentThreadId()));
  2220. UMRxDbgTrace(UMRX_TRACE_CONTEXT,
  2221. ("%ld: UMRxAsyncEngOuterWrapper: "
  2222. "RxContext: %08lx, Calling Routine: %s.\n",
  2223. PsGetCurrentThreadId(), RxContext, RoutineName));
  2224. SizeToAllocateInBytes = SIZEOF_UMRX_ASYNCENGINE_CONTEXT + AdditionalBytes;
  2225. //
  2226. // Try to create an AsyncEngContext for this operation. If unsuccessful,
  2227. // return failure.
  2228. //
  2229. AsyncEngineContext = UMRxCreateAsyncEngineContext(RxContext,
  2230. SizeToAllocateInBytes);
  2231. if (AsyncEngineContext == NULL) {
  2232. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2233. UMRxDbgTrace(UMRX_TRACE_ERROR,
  2234. ("%ld: ERROR: UMRxAsyncEngOuterWrapper/"
  2235. "UMRxCreateAsyncEngineContext: Error Val = %08lx\n",
  2236. PsGetCurrentThreadId(), NtStatus));
  2237. goto EXIT_THE_FUNCTION;
  2238. }
  2239. //
  2240. // Set the continuation routine.
  2241. //
  2242. AsyncEngineContext->Continuation = Continuation;
  2243. //
  2244. // If the Mini-Redir supplied a ContextFormatRoutine, now is the time to
  2245. // call it.
  2246. //
  2247. if (ContextFormatRoutine) {
  2248. NtStatus = ContextFormatRoutine(AsyncEngineContext, FormatContext);
  2249. if (NtStatus != STATUS_SUCCESS) {
  2250. UMRxDbgTrace(UMRX_TRACE_ERROR,
  2251. ("%ld: ERROR: UMRxAsyncEngOuterWrapper/"
  2252. "ContextFormatRoutine: Error Val = %08lx\n",
  2253. PsGetCurrentThreadId(), NtStatus));
  2254. goto EXIT_THE_FUNCTION;
  2255. }
  2256. }
  2257. //
  2258. // Now that we have the context ready, call the continuation routine.
  2259. //
  2260. if (Continuation) {
  2261. NtStatus = Continuation(UMRX_ASYNCENGINE_ARGUMENTS);
  2262. if ( NtStatus != STATUS_SUCCESS && NtStatus != STATUS_PENDING ) {
  2263. UMRxDbgTrace(UMRX_TRACE_ERROR,
  2264. ("%ld: ERROR: UMRxAsyncEngOuterWrapper/Continuation:"
  2265. " Error Val = %08lx, Calling Routine: %s.\n",
  2266. PsGetCurrentThreadId(), NtStatus, RoutineName));
  2267. }
  2268. }
  2269. EXIT_THE_FUNCTION:
  2270. if (NtStatus != STATUS_PENDING) {
  2271. if (AsyncEngineContext) {
  2272. BOOLEAN FinalizationComplete;
  2273. FinalizationComplete = UMRxFinalizeAsyncEngineContext( &(AsyncEngineContext) );
  2274. }
  2275. }
  2276. UMRxDbgTrace(UMRX_TRACE_ENTRYEXIT,
  2277. ("%ld: Leaving UMRxAsyncEngOuterWrapper with NtStatus = "
  2278. "%08lx\n", PsGetCurrentThreadId(), NtStatus));
  2279. return (NtStatus);
  2280. }
  2281. NTSTATUS
  2282. UMRxReadDWORDFromTheRegistry(
  2283. IN PWCHAR RegKey,
  2284. IN PWCHAR ValueToRead,
  2285. OUT LPDWORD DataRead
  2286. )
  2287. /*++
  2288. Routine Description:
  2289. This routine reads a DWORD value from the registry.
  2290. Arguments:
  2291. RegKey - The registry key who value needs to be read.
  2292. ValueToRead - The DWORD value to be read.
  2293. DataRead - The data is copied into this and returned back to the caller.
  2294. Return Value:
  2295. NTSTATUS value.
  2296. --*/
  2297. {
  2298. NTSTATUS NtStatus = STATUS_SUCCESS;
  2299. HKEY SubKey = NULL;
  2300. OBJECT_ATTRIBUTES ObjectAttributes;
  2301. UNICODE_STRING UnicodeKeyName, UnicodeValueName;
  2302. PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = NULL;
  2303. ULONG SizeInBytes = 0, SizeReturned = 0;
  2304. PAGED_CODE();
  2305. RtlInitUnicodeString(&(UnicodeKeyName), RegKey);
  2306. InitializeObjectAttributes(&(ObjectAttributes),
  2307. &(UnicodeKeyName),
  2308. OBJ_CASE_INSENSITIVE,
  2309. NULL,
  2310. NULL);
  2311. NtStatus = ZwOpenKey(&(SubKey), KEY_READ, &(ObjectAttributes));
  2312. if (NtStatus != STATUS_SUCCESS) {
  2313. DbgPrint("%ld: ERROR: UMRxReadDWORDFromTheRegistry/ZwOpenKey: NtStatus = %08lx\n",
  2314. PsGetCurrentThreadId(), NtStatus);
  2315. goto EXIT_THE_FUNCTION;
  2316. }
  2317. RtlInitUnicodeString(&(UnicodeValueName), ValueToRead);
  2318. //
  2319. // The size we need has to be the size of the structure plus the size of a
  2320. // DWORD since thats what we are going to be reading.
  2321. //
  2322. SizeInBytes = ( sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD) );
  2323. PartialInfo = RxAllocatePool(PagedPool, SizeInBytes);
  2324. if (PartialInfo == NULL) {
  2325. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2326. DbgPrint("%ld: ERROR: UMRxReadDWORDFromTheRegistry/RxAllocatePool: NtStatus = %08lx\n",
  2327. PsGetCurrentThreadId(), NtStatus);
  2328. goto EXIT_THE_FUNCTION;
  2329. }
  2330. NtStatus = ZwQueryValueKey(SubKey,
  2331. &(UnicodeValueName),
  2332. KeyValuePartialInformation,
  2333. (PVOID)PartialInfo,
  2334. SizeInBytes,
  2335. &(SizeReturned));
  2336. if (NtStatus != STATUS_SUCCESS) {
  2337. DbgPrint("%ld: ERROR: UMRxReadDWORDFromTheRegistry/ZwQueryValueKey: NtStatus = %08lx\n",
  2338. PsGetCurrentThreadId(), NtStatus);
  2339. goto EXIT_THE_FUNCTION;
  2340. }
  2341. RtlCopyMemory(DataRead, PartialInfo->Data, PartialInfo->DataLength);
  2342. EXIT_THE_FUNCTION:
  2343. if (SubKey) {
  2344. NtClose(SubKey);
  2345. SubKey = NULL;
  2346. }
  2347. if (PartialInfo) {
  2348. RxFreePool(PartialInfo);
  2349. }
  2350. return NtStatus;
  2351. }