Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1169 lines
35 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. RxContx.c
  5. Abstract:
  6. This module implements routine to allocate/initialize and to delete an Irp
  7. Context. These structures are very important because they link Irps with the
  8. RDBSS. They encapsulate all the context required to process an IRP.
  9. Author:
  10. Joe Linn [JoeLinn] 21-aug-1994
  11. Revision History:
  12. Balan Sethu Raman [SethuR] 07-June-1995 Included support for cancelling
  13. requests
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include <dfsfsctl.h>
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, RxInitializeContext)
  20. #pragma alloc_text(PAGE, RxReinitializeContext)
  21. #pragma alloc_text(PAGE, RxPrepareContextForReuse)
  22. #pragma alloc_text(PAGE, RxCompleteRequest)
  23. #pragma alloc_text(PAGE, __RxSynchronizeBlockingOperationsMaybeDroppingFcbLock)
  24. #pragma alloc_text(PAGE, RxResumeBlockedOperations_Serially)
  25. #pragma alloc_text(PAGE, RxResumeBlockedOperations_ALL)
  26. #pragma alloc_text(PAGE, RxCancelBlockingOperation)
  27. #pragma alloc_text(PAGE, RxRemoveOperationFromBlockingQueue)
  28. #endif
  29. BOOLEAN RxSmallContextLogEntry = FALSE;
  30. FAST_MUTEX RxContextPerFileSerializationMutex;
  31. //
  32. // The debug trace level
  33. //
  34. #define Dbg (DEBUG_TRACE_RXCONTX)
  35. ULONG RxContextSerialNumberCounter = 0;
  36. #ifdef RDBSSLOG
  37. //this stuff must be in nonpaged memory
  38. //// 1 2 3 4 5 6 7 8 9
  39. char RxInitContext_SurrogateFormat[] = "%S%S%N%N%N%N%N%N%N";
  40. //// 2 3 4 5 6 7 8 9
  41. char RxInitContext_ActualFormat[] = "Irp++ %s/%lx %08lx irp %lx thrd %lx %lx:%lx #%lx";
  42. #endif //ifdef RDBSSLOG
  43. VOID
  44. ValidateBlockingIoQ(
  45. PLIST_ENTRY BlockingIoQ
  46. );
  47. VOID
  48. RxInitializeContext(
  49. IN PIRP Irp,
  50. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  51. IN ULONG InitialContextFlags,
  52. IN OUT PRX_CONTEXT RxContext)
  53. {
  54. PDEVICE_OBJECT TopLevelDeviceObject;
  55. PAGED_CODE();
  56. RxDbgTrace(+1, Dbg, ("RxInitializeContext\n"));
  57. // some asserts that we need. This ensures that the two values that are
  58. // packaged together as an IoStatusBlock can be manipulated independently
  59. // as well as together.
  60. ASSERT(
  61. FIELD_OFFSET(RX_CONTEXT,StoredStatus) ==
  62. FIELD_OFFSET(RX_CONTEXT,IoStatusBlock.Status));
  63. ASSERT(
  64. FIELD_OFFSET(RX_CONTEXT,InformationToReturn) ==
  65. FIELD_OFFSET(RX_CONTEXT,IoStatusBlock.Information));
  66. // Set the proper node type code, node byte size and the flags
  67. RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT;
  68. RxContext->NodeByteSize = sizeof(RX_CONTEXT);
  69. RxContext->ReferenceCount = 1;
  70. RxContext->SerialNumber = InterlockedIncrement(&RxContextSerialNumberCounter);
  71. RxContext->RxDeviceObject = RxDeviceObject;
  72. // Initialize the Sync Event.
  73. KeInitializeEvent(
  74. &RxContext->SyncEvent,
  75. SynchronizationEvent,
  76. FALSE);
  77. // Initialize the associated scavenger entry
  78. RxInitializeScavengerEntry(&RxContext->ScavengerEntry);
  79. // Initialize the list entry of blocked operations
  80. InitializeListHead(&RxContext->BlockedOperations);
  81. RxContext->MRxCancelRoutine = NULL;
  82. RxContext->ResumeRoutine = NULL;
  83. SetFlag( RxContext->Flags, InitialContextFlags);
  84. // Set the Irp fields....for cacheing and hiding
  85. RxContext->CurrentIrp = Irp;
  86. RxContext->OriginalThread = RxContext->LastExecutionThread = PsGetCurrentThread();
  87. if (Irp != NULL) {
  88. PIO_STACK_LOCATION IrpSp;
  89. IrpSp = IoGetCurrentIrpStackLocation( Irp ); //ok4ioget
  90. // There are certain operations that are open ended in the redirector.
  91. // The change notification mechanism is one of them. On a synchronous
  92. // operation if the wait is in the redirector then we will not be able
  93. // to cancel because FsRtlEnterFileSystem disables APC's. Therefore
  94. // we convert the synchronous operation into an asynchronous one and
  95. // let the I/O system do the waiting.
  96. if (IrpSp->FileObject != NULL) {
  97. if (!IoIsOperationSynchronous(Irp)) {
  98. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  99. } else {
  100. PFCB Fcb;
  101. Fcb = (PFCB)IrpSp->FileObject->FsContext;
  102. if ((Fcb != NULL) && NodeTypeIsFcb(Fcb)) {
  103. if (((IrpSp->MajorFunction == IRP_MJ_READ) ||
  104. (IrpSp->MajorFunction == IRP_MJ_WRITE) ||
  105. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)) &&
  106. (Fcb->pNetRoot != NULL) &&
  107. (Fcb->pNetRoot->Type == NET_ROOT_PIPE)) {
  108. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  109. }
  110. }
  111. }
  112. }
  113. if ((IrpSp->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
  114. (IrpSp->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)) {
  115. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  116. }
  117. //
  118. // JOYC: make all device io control async
  119. //
  120. if (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
  121. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION );
  122. }
  123. // Set the recursive file system call parameter. We set it true if
  124. // the TopLevelIrp field in the thread local storage is not the current
  125. // irp, otherwise we leave it as FALSE.
  126. if ( !RxIsThisTheTopLevelIrp(Irp) ) {
  127. SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL);
  128. }
  129. if ( RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject ) {
  130. SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL);
  131. }
  132. // Major/Minor Function codes
  133. RxContext->MajorFunction = IrpSp->MajorFunction;
  134. RxContext->MinorFunction = IrpSp->MinorFunction;
  135. ASSERT(RxContext->MajorFunction<=IRP_MJ_MAXIMUM_FUNCTION);
  136. RxContext->CurrentIrpSp = IrpSp;
  137. if (IrpSp->FileObject) {
  138. PFOBX Fobx;
  139. PFCB Fcb;
  140. Fcb = (PFCB)IrpSp->FileObject->FsContext;
  141. Fobx = (PFOBX)IrpSp->FileObject->FsContext2;
  142. RxContext->pFcb = (PMRX_FCB)Fcb;
  143. if (Fcb && NodeTypeIsFcb(Fcb)) {
  144. RxContext->NonPagedFcb = Fcb->NonPaged;
  145. }
  146. if (Fobx &&
  147. (Fobx != (PFOBX)UIntToPtr(DFS_OPEN_CONTEXT)) &&
  148. (Fobx != (PFOBX)UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT))) {
  149. RxContext->pFobx = (PMRX_FOBX)Fobx;
  150. RxContext->pRelevantSrvOpen = Fobx->pSrvOpen;
  151. if (NodeType(Fobx)==RDBSS_NTC_FOBX) {
  152. RxContext->FobxSerialNumber = InterlockedIncrement(&Fobx->FobxSerialNumber);
  153. }
  154. } else {
  155. RxContext->pFobx = NULL;
  156. }
  157. // Copy IRP specific parameters.
  158. if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
  159. (RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY)) {
  160. if (Fobx != NULL) {
  161. if (NodeType(Fobx)==RDBSS_NTC_FOBX) {
  162. RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)Fcb->VNetRoot;
  163. } else if (NodeType(Fobx) == RDBSS_NTC_V_NETROOT) {
  164. RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)Fobx;
  165. }
  166. }
  167. }
  168. // Copy RealDevice for workque algorithms,
  169. RxContext->RealDevice = IrpSp->FileObject->DeviceObject;
  170. if (FlagOn(IrpSp->FileObject->Flags,FO_WRITE_THROUGH)){
  171. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH );
  172. }
  173. }
  174. } else {
  175. RxContext->CurrentIrpSp = NULL;
  176. // Major/Minor Function codes
  177. RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1;
  178. RxContext->MinorFunction = 0;
  179. }
  180. if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
  181. PETHREAD Thread = PsGetCurrentThread();
  182. UCHAR Pad = 0;
  183. RxLog(
  184. (
  185. RxInitContext_SurrogateFormat,
  186. RxInitContext_ActualFormat,
  187. RXCONTX_OPERATION_NAME(
  188. RxContext->MajorFunction,
  189. BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT)),
  190. RxContext->MinorFunction,
  191. RxContext,
  192. Irp,
  193. Thread,
  194. RxContext->pFcb,
  195. RxContext->pFobx,
  196. RxContext->SerialNumber
  197. ));
  198. RxWmiLog(LOG,
  199. RxInitializeContext,
  200. LOGPTR(RxContext)
  201. LOGPTR(Irp)
  202. LOGPTR(Thread)
  203. LOGPTR(RxContext->pFcb)
  204. LOGPTR(RxContext->pFobx)
  205. LOGULONG(RxContext->SerialNumber)
  206. LOGUCHAR(RxContext->MinorFunction)
  207. LOGARSTR(RXCONTX_OPERATION_NAME(
  208. RxContext->MajorFunction,
  209. BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT))));
  210. }
  211. RxDbgTrace(-1, Dbg, ("RxInitializeContext -> %08lx %08lx %08lx\n",
  212. RxContext,RxContext->pFcb,RxContext->pFobx));
  213. }
  214. PRX_CONTEXT
  215. RxCreateRxContext (
  216. IN PIRP Irp,
  217. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  218. IN ULONG InitialContextFlags
  219. )
  220. /*++
  221. Routine Description:
  222. This routine creates a new RX_CONTEXT record
  223. Arguments:
  224. Irp - Supplies the originating Irp.
  225. RxDeviceObject - the deviceobject that applies
  226. InitialContextFlags - Supplies the wait value to store in the context;
  227. also, the must_succeed value
  228. Return Value:
  229. PRX_CONTEXT - returns a pointer to the newly allocate RX_CONTEXT Record
  230. --*/
  231. {
  232. KIRQL SavedIrql;
  233. PRX_CONTEXT RxContext = NULL;
  234. ULONG RxContextFlags = 0;
  235. UCHAR MustSucceedDescriptorNumber = 0;
  236. DebugDoit( InterlockedIncrement(&RxFsdEntryCount); )
  237. ASSERT(RxDeviceObject!=NULL);
  238. InterlockedIncrement(&RxDeviceObject->NumberOfActiveContexts);
  239. if (RxContext == NULL) {
  240. RxContext = ExAllocateFromNPagedLookasideList(
  241. &RxContextLookasideList);
  242. if (RxContext != NULL) {
  243. SetFlag( RxContextFlags, RX_CONTEXT_FLAG_FROM_POOL );
  244. }
  245. }
  246. if(RxContext == NULL){
  247. return(NULL);
  248. }
  249. RtlZeroMemory( RxContext, sizeof(RX_CONTEXT) );
  250. RxContext->Flags = RxContextFlags;
  251. RxContext->MustSucceedDescriptorNumber = MustSucceedDescriptorNumber;
  252. RxInitializeContext(Irp,RxDeviceObject,InitialContextFlags,RxContext);
  253. ASSERT(
  254. (RxContext->MajorFunction!=IRP_MJ_CREATE) ||
  255. !FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED) );
  256. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  257. InsertTailList(&RxActiveContexts,&RxContext->ContextListEntry);
  258. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  259. return RxContext;
  260. }
  261. VOID
  262. RxReinitializeContext(
  263. IN OUT PRX_CONTEXT RxContext
  264. )
  265. {
  266. PIRP Irp = RxContext->CurrentIrp;
  267. PRDBSS_DEVICE_OBJECT RxDeviceObject = RxContext->RxDeviceObject;
  268. ULONG PreservedContextFlags = RxContext->Flags & RX_CONTEXT_PRESERVED_FLAGS;
  269. ULONG InitialContextFlags = RxContext->Flags & RX_CONTEXT_INITIALIZATION_FLAGS;
  270. PAGED_CODE();
  271. RxPrepareContextForReuse(RxContext);
  272. RtlZeroMemory(
  273. (PCHAR)(&RxContext->ContextListEntry + 1),
  274. sizeof(RX_CONTEXT) - FIELD_OFFSET(RX_CONTEXT,MajorFunction));
  275. RxContext->Flags = PreservedContextFlags;
  276. RxInitializeContext(Irp,RxDeviceObject,InitialContextFlags,RxContext);
  277. }
  278. VOID
  279. RxPrepareContextForReuse(
  280. IN OUT PRX_CONTEXT RxContext)
  281. /*++
  282. Routine Description:
  283. This routine prepares a context for reuse by resetting all operation specific
  284. allocations/acquistions that have been made. The parameters that have been
  285. obtained from the IRP are not modified.
  286. Arguments:
  287. RxContext - Supplies the RX_CONTEXT to remove
  288. Return Value:
  289. None
  290. --*/
  291. {
  292. PAGED_CODE();
  293. // Clean up the operation specific stuff
  294. switch (RxContext->MajorFunction) {
  295. case IRP_MJ_CREATE:
  296. ASSERT ( RxContext->Create.CanonicalNameBuffer == NULL );
  297. break;
  298. case IRP_MJ_READ :
  299. case IRP_MJ_WRITE :
  300. {
  301. ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL);
  302. ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL);
  303. }
  304. break;
  305. default:
  306. NOTHING;
  307. }
  308. RxContext->ReferenceCount = 0;
  309. }
  310. VOID
  311. RxDereferenceAndDeleteRxContext_Real (
  312. IN PRX_CONTEXT RxContext
  313. )
  314. /*++
  315. Routine Description:
  316. This routine dereferences an RxContexts and if the refcount goes to zero
  317. then it deallocates and removes the specified RX_CONTEXT record from the
  318. Rx in-memory data structures. IT is called by routines other than
  319. RxCompleteRequest async requests touch the RxContext "last" in either the
  320. initiating thread or in some other thread. Thus, we refcount the structure
  321. and finalize on the last dereference.
  322. Arguments:
  323. RxContext - Supplies the RX_CONTEXT to remove
  324. Return Value:
  325. None
  326. --*/
  327. {
  328. KIRQL SavedIrql;
  329. BOOLEAN RxContextIsFromPool;
  330. BOOLEAN RxContextIsMustSucceedAllocated;
  331. BOOLEAN RxContextIsFromZone;
  332. PRDBSS_DEVICE_OBJECT RxDeviceObject;
  333. PRX_CONTEXT pStopContext = NULL;
  334. LONG FinalRefCount;
  335. RxDbgTraceLV(+1, Dbg, 1500, ("RxDereferenceAndDeleteRxContext, RxContext = %08lx (%lu)\n",
  336. RxContext,RxContext->SerialNumber));
  337. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  338. ASSERT( RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT );
  339. FinalRefCount = InterlockedDecrement(&RxContext->ReferenceCount);
  340. if (FinalRefCount == 0) {
  341. RxDeviceObject = RxContext->RxDeviceObject;
  342. RxContextIsFromPool = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL);
  343. RxContextIsMustSucceedAllocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED);
  344. if (RxContext == RxDeviceObject->StartStopContext.pStopContext) {
  345. RxDeviceObject->StartStopContext.pStopContext = NULL;
  346. } else {
  347. ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) &&
  348. (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry));
  349. RemoveEntryList(&RxContext->ContextListEntry);
  350. if ((InterlockedDecrement(&RxDeviceObject->NumberOfActiveContexts)==0) &&
  351. (RxDeviceObject->StartStopContext.pStopContext != NULL)) {
  352. pStopContext = RxDeviceObject->StartStopContext.pStopContext;
  353. }
  354. }
  355. }
  356. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  357. if (FinalRefCount > 0) {
  358. RxDbgTraceLV(-1, Dbg, 1500, ("RxDereferenceAndDeleteRxContext, RxContext not final!!! = %08lx (%lu)\n",
  359. RxContext,RxContext->SerialNumber));
  360. return;
  361. }
  362. ASSERT(RxContext->ReferenceCount == 0);
  363. // Clean up the operation specific stuff
  364. RxPrepareContextForReuse(RxContext);
  365. ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
  366. if (pStopContext != NULL) {
  367. // Signal the event.
  368. RxSignalSynchronousWaiter(pStopContext);
  369. }
  370. if (RxContext->dwShadowCritOwner)
  371. {
  372. DbgPrint("RxDereferenceAndDeleteRxContext:shdowcrit still owned by %x\n", RxContext->dwShadowCritOwner);
  373. ASSERT(FALSE);
  374. }
  375. if (RxContextIsFromPool) {
  376. ExFreeToNPagedLookasideList(
  377. &RxContextLookasideList,
  378. RxContext );
  379. }
  380. RxDbgTraceLV(-1, Dbg, 1500, ("RxDereferenceAndDeleteRxContext -> VOID\n", 0));
  381. return;
  382. }
  383. ULONG RxStopOnLoudCompletion = TRUE;
  384. NTSTATUS
  385. RxCompleteRequest(
  386. IN PRX_CONTEXT RxContext,
  387. IN NTSTATUS Status)
  388. {
  389. PIRP Irp;
  390. PAGED_CODE();
  391. ASSERT(RxContext);
  392. ASSERT(RxContext->CurrentIrp);
  393. Irp = RxContext->CurrentIrp;
  394. if ((RxContext->LoudCompletionString)) {
  395. DbgPrint("LoudCompletion %08lx/%08lx on %wZ\n",Status,Irp->IoStatus.Information,RxContext->LoudCompletionString);
  396. if ((Status!=STATUS_SUCCESS) && RxStopOnLoudCompletion) {
  397. DbgPrint("FAILURE!!!!! %08lx/%08lx on %wZ\n",Status,Irp->IoStatus.Information,RxContext->LoudCompletionString);
  398. //DbgBreakPoint();
  399. }
  400. }
  401. #if 0
  402. if ((Status!=STATUS_SUCCESS) && (RxContext->LoudCompletionString)) {
  403. DbgPrint("LoudFailure %08lx/%08lx on %wZ\n",Status,Irp->IoStatus.Information,RxContext->LoudCompletionString);
  404. if (RxStopOnLoudCompletion) {
  405. //DbgBreakPoint();
  406. }
  407. }
  408. #endif
  409. RxContext->CurrentIrp = NULL;
  410. RxCompleteRequest_Real(RxContext,Irp,Status);
  411. return Status;
  412. }
  413. #ifdef RDBSSLOG
  414. //this stuff must be in nonpaged memory
  415. //// 1 2 3 4 5 6 7 8 9
  416. char RxCompleteContext_SurrogateFormat[] = "%S%S%S%N%N%N%N%N%N";
  417. //// 2 3 4 5 6 7 8 9
  418. char RxCompleteContext_ActualFormat[] = "Irp-- %s%s/%lx %lx irp %lx iosb %lx,%lx #%lx";
  419. #endif //ifdef RDBSSLOG
  420. VOID
  421. RxCompleteRequest_Real (
  422. IN PRX_CONTEXT RxContext,
  423. IN PIRP Irp OPTIONAL,
  424. IN NTSTATUS Status
  425. )
  426. /*++
  427. Routine Description:
  428. This routine completes a Irp
  429. Arguments:
  430. Irp - Supplies the Irp being processed
  431. Status - Supplies the status to complete the Irp with
  432. --*/
  433. {
  434. //
  435. // If we have an Irp then complete the irp.
  436. //
  437. if (Irp != NULL) {
  438. CCHAR PriorityBoost;
  439. PIO_STACK_LOCATION IrpSp;
  440. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  441. RxSetCancelRoutine(Irp,NULL);
  442. //
  443. // For an error, zero out the information field before
  444. // completing the request if this was an input operation.
  445. // Otherwise IopCompleteRequest will try to copy to the user's buffer.
  446. // Also, no boost for an error.
  447. //
  448. if ( NT_ERROR(Status) &&
  449. FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) {
  450. Irp->IoStatus.Information = 0;
  451. PriorityBoost = IO_NO_INCREMENT;
  452. } else {
  453. PriorityBoost = IO_DISK_INCREMENT;
  454. }
  455. if (Irp->MdlAddress) {
  456. RxUnprotectMdlFromFree(Irp->MdlAddress);
  457. }
  458. Irp->IoStatus.Status = Status;
  459. RxDbgTrace(0, (DEBUG_TRACE_DISPATCH),
  460. ("RxCompleteRequest_real ---------- Irp(code) = %08lx(%02lx) %08lx %08lx\n",
  461. Irp, IoGetCurrentIrpStackLocation( Irp )->MajorFunction,
  462. Status, Irp->IoStatus.Information));
  463. if (RxContext != NULL) {
  464. ASSERT(RxContext->MajorFunction<=IRP_MJ_MAXIMUM_FUNCTION);
  465. if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL) {
  466. RxLog(
  467. (
  468. RxCompleteContext_SurrogateFormat,
  469. RxCompleteContext_ActualFormat,
  470. (RxContext->OriginalThread == PsGetCurrentThread())?"":"*",
  471. RXCONTX_OPERATION_NAME(RxContext->MajorFunction,TRUE),
  472. RxContext->MinorFunction,
  473. RxContext,
  474. Irp,
  475. Status,
  476. Irp->IoStatus.Information,
  477. RxContext->SerialNumber
  478. ));
  479. RxWmiLog(LOG,
  480. RxCompleteRequest,
  481. LOGPTR(RxContext)
  482. LOGPTR(Irp)
  483. LOGULONG(Status)
  484. LOGPTR(Irp->IoStatus.Information)
  485. LOGULONG(RxContext->SerialNumber)
  486. LOGUCHAR(RxContext->MinorFunction)
  487. LOGARSTR(RXCONTX_OPERATION_NAME(RxContext->MajorFunction,TRUE)));
  488. }
  489. }
  490. if ((IrpSp->MajorFunction == IRP_MJ_CREATE) &&
  491. (Status != STATUS_PENDING)) {
  492. if (RxContext != NULL) {
  493. if (FlagOn(
  494. RxContext->Create.Flags,
  495. RX_CONTEXT_CREATE_FLAG_STRIPPED_TRAILING_BACKSLASH)) {
  496. IrpSp->FileObject->FileName.Length += sizeof(WCHAR);
  497. }
  498. RxpPrepareCreateContextForReuse(RxContext);
  499. ASSERT ( RxContext->Create.CanonicalNameBuffer == NULL );
  500. }
  501. }
  502. if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
  503. if (Irp->IoStatus.Status == STATUS_SUCCESS) {
  504. ASSERT(Irp->IoStatus.Information <= IrpSp->Parameters.Write.Length);
  505. }
  506. }
  507. if (RxContext != NULL) {
  508. if (RxContext->PendingReturned) {
  509. ASSERT(IrpSp->Control & SL_PENDING_RETURNED);
  510. }
  511. }
  512. IoCompleteRequest( Irp, PriorityBoost );
  513. } else {
  514. // a call with a null irp..........
  515. RxLog(("Irp00 %lx\n", RxContext ));
  516. RxWmiLog(LOG,
  517. RxCompleteRequest_NI,
  518. LOGPTR(RxContext));
  519. }
  520. // Delete the Irp context.
  521. if (RxContext != NULL) {
  522. RxDereferenceAndDeleteRxContext( RxContext );
  523. }
  524. return;
  525. }
  526. NTSTATUS
  527. __RxSynchronizeBlockingOperationsMaybeDroppingFcbLock(
  528. IN OUT PRX_CONTEXT RxContext,
  529. IN OUT PLIST_ENTRY BlockingIoQ,
  530. IN BOOLEAN DropFcbLock
  531. )
  532. /*++
  533. Routine Description:
  534. This routine is used to synchronize among blocking IOs to the same Q.
  535. Currently, the routine is only used to synchronize block pipe operations and
  536. the Q is the one in the file object extension (Fobx). What happens is that
  537. the operation joins the queue. If it is now the front of the queue, the
  538. operation continues; otherwise it waits on the sync event in the RxContext
  539. or just returns pending (if async).
  540. We may have been cancelled while we slept, check for that and
  541. return an error if it happens.
  542. The event must have been reset before the call. The fcb lock must be held;
  543. it is dropped after we get on the Q.
  544. Arguments:
  545. RxContext The context of the operation being synchronized
  546. BlockingIoQ The queue to get on.
  547. --*/
  548. {
  549. NTSTATUS Status;
  550. RxCaptureFcb;
  551. RxCaptureRequestPacket;
  552. BOOLEAN FcbLockDropped = FALSE;
  553. BOOLEAN SerializationMutexReleased = FALSE;
  554. PRX_CONTEXT FrontRxContext;
  555. PAGED_CODE();
  556. RxDbgTrace(+1, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock, rxc=%08lx, fobx=%08lx\n", RxContext, RxContext->pFobx ));
  557. RxContext->StoredStatus = STATUS_SUCCESS; //do this early....a cleanup could come thru and change it
  558. ExAcquireFastMutex(&RxContextPerFileSerializationMutex);
  559. if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED)) {
  560. SetFlag(
  561. RxContext->FlagsForLowIo,
  562. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
  563. // ValidateBlockingIoQ(BlockingIoQ);
  564. InsertTailList(BlockingIoQ,&RxContext->RxContextSerializationQLinks);
  565. FrontRxContext = CONTAINING_RECORD( BlockingIoQ->Flink,RX_CONTEXT,RxContextSerializationQLinks);
  566. if (RxContext != FrontRxContext) {
  567. if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  568. if (!SerializationMutexReleased) {
  569. SerializationMutexReleased = TRUE;
  570. ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
  571. }
  572. if (DropFcbLock && !FcbLockDropped) {
  573. RxContext->FcbResourceAcquired = FALSE;
  574. FcbLockDropped = TRUE;
  575. RxReleaseFcb(RxContext,capFcb);
  576. }
  577. RxDbgTrace( 0, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock waiting, rxc=%08lx\n", RxContext ));
  578. RxWaitSync(RxContext);
  579. RxDbgTrace( 0, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock ubblocked, rxc=%08lx\n", RxContext ));
  580. } else {
  581. RxContext->StoredStatus = STATUS_PENDING;
  582. SetFlag(RxContext->Flags,RX_CONTEXT_FLAG_BLOCKED_PIPE_RESUME);
  583. try {
  584. RxPrePostIrp(RxContext,capReqPacket);
  585. } finally {
  586. if (AbnormalTermination()) {
  587. RxLog(("!!!!! RxContext %lx Status %lx\n",RxContext, RxContext->StoredStatus));
  588. RxWmiLog(LOG,
  589. RxSynchronizeBlockingOperationsMaybeDroppingFcbLock,
  590. LOGPTR(RxContext)
  591. LOGULONG(Status));
  592. RemoveEntryList(&RxContext->RxContextSerializationQLinks);
  593. RxContext->RxContextSerializationQLinks.Flink = NULL;
  594. RxContext->RxContextSerializationQLinks.Blink = NULL;
  595. ClearFlag(
  596. RxContext->FlagsForLowIo,
  597. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
  598. if (!SerializationMutexReleased) {
  599. SerializationMutexReleased = TRUE;
  600. ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
  601. }
  602. } else {
  603. InterlockedIncrement(&RxContext->ReferenceCount);
  604. }
  605. }
  606. RxDbgTrace(-1, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock asyncreturn, rxc=%08lx\n", RxContext ));
  607. }
  608. }
  609. Status = (FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED) ?
  610. STATUS_CANCELLED :
  611. RxContext->StoredStatus);
  612. } else {
  613. Status = STATUS_CANCELLED;
  614. }
  615. if (!SerializationMutexReleased) {
  616. SerializationMutexReleased = TRUE;
  617. ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
  618. }
  619. if (DropFcbLock && !FcbLockDropped) {
  620. RxContext->FcbResourceAcquired = FALSE;
  621. FcbLockDropped = TRUE;
  622. RxReleaseFcb(RxContext,capFcb);
  623. }
  624. RxDbgTrace(-1, Dbg, ("RxSynchronizeBlockingOperationsAndDropFcbLock returning, rxc=%08lx, status=%08lx\n", RxContext, Status ));
  625. return(Status);
  626. }
  627. VOID
  628. RxRemoveOperationFromBlockingQueue(
  629. IN OUT PRX_CONTEXT RxContext)
  630. /*++
  631. Routine Description:
  632. This routine removes the context from the blocking queue if it is on it
  633. Arguments:
  634. RxContext The context of the operation being synchronized
  635. --*/
  636. {
  637. PAGED_CODE();
  638. ExAcquireFastMutex(&RxContextPerFileSerializationMutex);
  639. if (FlagOn(
  640. RxContext->FlagsForLowIo,
  641. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) {
  642. ClearFlag(
  643. RxContext->FlagsForLowIo,
  644. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
  645. RemoveEntryList(&RxContext->RxContextSerializationQLinks);
  646. RxContext->RxContextSerializationQLinks.Flink = NULL;
  647. RxContext->RxContextSerializationQLinks.Blink = NULL;
  648. }
  649. ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
  650. RxDbgTrace(-1, Dbg, ("RxRemoveOperationFromBlockingQueue, rxc=%08lx\n", RxContext ));
  651. return;
  652. }
  653. VOID
  654. RxCancelBlockingOperation(
  655. IN OUT PRX_CONTEXT RxContext)
  656. /*++
  657. Routine Description:
  658. This routine cancels the operation in the blocking queue
  659. Arguments:
  660. RxContext The context of the operation being synchronized
  661. --*/
  662. {
  663. PAGED_CODE();
  664. ExAcquireFastMutex(&RxContextPerFileSerializationMutex);
  665. if (FlagOn(
  666. RxContext->FlagsForLowIo,
  667. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) {
  668. ClearFlag(
  669. RxContext->FlagsForLowIo,
  670. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
  671. RemoveEntryList(&RxContext->RxContextSerializationQLinks);
  672. RxContext->RxContextSerializationQLinks.Flink = NULL;
  673. RxContext->RxContextSerializationQLinks.Blink = NULL;
  674. if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  675. RxSignalSynchronousWaiter(RxContext);
  676. } else {
  677. // The reference taken in the synchronization routine is derefernced
  678. // by the post completion routine,
  679. RxFsdPostRequest(RxContext);
  680. }
  681. }
  682. ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
  683. RxDbgTrace(-1, Dbg, ("RxCancelBlockedOperations, rxc=%08lx\n", RxContext ));
  684. return;
  685. }
  686. VOID
  687. RxResumeBlockedOperations_Serially(
  688. IN OUT PRX_CONTEXT RxContext,
  689. IN OUT PLIST_ENTRY BlockingIoQ
  690. )
  691. /*++
  692. Routine Description:
  693. This routine wakes up the next guy, if any, on the serialized blockingioQ. We know that the fcb must still be valid because
  694. of the reference that is being held by the IO system on the file object thereby preventing a close.
  695. Arguments:
  696. RxContext The context of the operation being synchronized
  697. BlockingIoQ The queue to get on.
  698. --*/
  699. {
  700. PLIST_ENTRY ListEntry;
  701. BOOLEAN FcbLockHeld = FALSE;
  702. PRX_CONTEXT FrontRxContext = NULL;
  703. PAGED_CODE();
  704. RxDbgTrace(
  705. +1,
  706. Dbg,
  707. ("RxResumeBlockedOperations_Serially, rxc=%08lx, fobx=%08lx\n",
  708. RxContext,
  709. RxContext->pFobx ));
  710. //remove myself from the queue and check for someone else
  711. ExAcquireFastMutex(&RxContextPerFileSerializationMutex);
  712. if (FlagOn(
  713. RxContext->FlagsForLowIo,
  714. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) {
  715. ClearFlag(
  716. RxContext->FlagsForLowIo,
  717. RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION);
  718. // ValidateBlockingIoQ(BlockingIoQ);
  719. RemoveEntryList(&RxContext->RxContextSerializationQLinks);
  720. // ValidateBlockingIoQ(BlockingIoQ);
  721. RxContext->RxContextSerializationQLinks.Flink = NULL;
  722. RxContext->RxContextSerializationQLinks.Blink = NULL;
  723. ListEntry = BlockingIoQ->Flink;
  724. if (BlockingIoQ != ListEntry) {
  725. FrontRxContext = CONTAINING_RECORD(
  726. ListEntry,
  727. RX_CONTEXT,
  728. RxContextSerializationQLinks);
  729. RxDbgTrace(
  730. -1,
  731. Dbg,
  732. ("RxResumeBlockedOperations unwaiting the next guy and returning, rxc=%08lx\n",
  733. RxContext ));
  734. } else {
  735. FrontRxContext = NULL;
  736. }
  737. if (FrontRxContext != NULL) {
  738. if (!FlagOn(FrontRxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION)) {
  739. RxSignalSynchronousWaiter(FrontRxContext);
  740. } else {
  741. // The reference taken in the synchronization routine is derefernced
  742. // by the post completion routine,
  743. RxFsdPostRequest(FrontRxContext);
  744. }
  745. }
  746. }
  747. ExReleaseFastMutex(&RxContextPerFileSerializationMutex);
  748. RxDbgTrace(-1, Dbg, ("RxResumeBlockedOperations_Serially returning, rxc=%08lx\n", RxContext ));
  749. return;
  750. }
  751. VOID
  752. RxResumeBlockedOperations_ALL(
  753. IN OUT PRX_CONTEXT RxContext
  754. )
  755. /*++
  756. Routine Description:
  757. This routine wakes up all of the guys on the blocked operations queue. The controlling mutex is also
  758. stored in the RxContext block. the current implementation is that all of the guys must be waiting
  759. on the sync events.
  760. Arguments:
  761. RxContext The context of the operation being synchronized
  762. --*/
  763. {
  764. LIST_ENTRY CopyOfQueue;
  765. PLIST_ENTRY ListEntry;
  766. PAGED_CODE();
  767. RxDbgTrace(+1, Dbg, ("RxResumeBlockedOperations_ALL, rxc=%08lx\n", RxContext ));
  768. RxTransferListWithMutex(
  769. &CopyOfQueue,
  770. &RxContext->BlockedOperations,
  771. RxContext->BlockedOpsMutex);
  772. for (ListEntry = CopyOfQueue.Flink;
  773. ListEntry != &CopyOfQueue;
  774. ){
  775. PRX_CONTEXT FrontRxContext = CONTAINING_RECORD(
  776. ListEntry,
  777. RX_CONTEXT,
  778. RxContextSerializationQLinks);
  779. RxSignalSynchronousWaiter(FrontRxContext);
  780. IF_DEBUG {
  781. PLIST_ENTRY PrevListEntry = ListEntry;
  782. ListEntry = ListEntry->Flink;
  783. PrevListEntry->Flink = PrevListEntry->Blink = NULL;
  784. } else {
  785. ListEntry = ListEntry->Flink;
  786. }
  787. }
  788. RxDbgTrace(
  789. -1,
  790. Dbg,
  791. ("RxResumeBlockedOperations_ALL returning, rxc=%08lx\n",
  792. RxContext ));
  793. return;
  794. }
  795. VOID
  796. __RxItsTheSameContext(
  797. PRX_CONTEXT RxContext,
  798. ULONG CapturedRxContextSerialNumber,
  799. ULONG Line,
  800. PSZ File
  801. )
  802. {
  803. if ((NodeType(RxContext)!=RDBSS_NTC_RX_CONTEXT) ||
  804. (RxContext->SerialNumber != CapturedRxContextSerialNumber)) {
  805. RxLog(("NotSame!!!! %lx",RxContext));
  806. RxWmiLog(LOG,
  807. RxItsTheSameContext,
  808. LOGPTR(RxContext));
  809. DbgPrint("NOT THE SAME CONTEXT %08lx at Line %d in %s\n",
  810. RxContext,Line,File);
  811. //DbgBreakPoint();
  812. }
  813. }
  814. #if 0
  815. VOID
  816. ValidateBlockingIoQ(
  817. PLIST_ENTRY BlockingIoQ
  818. )
  819. {
  820. PLIST_ENTRY pListEntry;
  821. ULONG cntFlink, cntBlink;
  822. cntFlink = cntBlink = 0;
  823. pListEntry = BlockingIoQ->Flink;
  824. while (pListEntry != BlockingIoQ) {
  825. PRX_CONTEXT pRxContext;
  826. pRxContext = (PRX_CONTEXT)CONTAINING_RECORD(
  827. pListEntry,
  828. RX_CONTEXT,
  829. RxContextSerializationQLinks);
  830. if (!pRxContext || (NodeType(pRxContext) != RDBSS_NTC_RX_CONTEXT))
  831. {
  832. DbgPrint("ValidateBlockingIO:Invalid RxContext %x on Q %x\n",
  833. pRxContext, BlockingIoQ);
  834. //DbgBreakPoint();
  835. }
  836. ++cntFlink;
  837. pListEntry = pListEntry->Flink;
  838. }
  839. // check backward list validity
  840. pListEntry = BlockingIoQ->Blink;
  841. while (pListEntry != BlockingIoQ) {
  842. PRX_CONTEXT pRxContext;
  843. pRxContext = (PRX_CONTEXT)CONTAINING_RECORD(
  844. pListEntry,
  845. RX_CONTEXT,
  846. RxContextSerializationQLinks);
  847. if (!pRxContext || (NodeType(pRxContext) != RDBSS_NTC_RX_CONTEXT))
  848. {
  849. DbgPrint("ValidateBlockingIO:Invalid RxContext %x on Q %x\n",
  850. pRxContext, BlockingIoQ);
  851. //DbgBreakPoint();
  852. }
  853. ++cntBlink;
  854. pListEntry = pListEntry->Blink;
  855. }
  856. // both counts should be the same
  857. if(cntFlink != cntBlink)
  858. {
  859. DbgPrint("ValidateBlockingIO: cntFlink %d cntBlink %d\n", cntFlink, cntBlink);
  860. //DbgBreakPoint();
  861. }
  862. }
  863. #endif
  864. #ifndef RX_NO_DBGFIELD_HLPRS
  865. #define DECLARE_FIELD_HLPR(x) ULONG RxContextField_##x = FIELD_OFFSET(RX_CONTEXT,x);
  866. #define DECLARE_FIELD_HLPR2(x,y) ULONG RxContextField_##x##y = FIELD_OFFSET(RX_CONTEXT,x.y);
  867. DECLARE_FIELD_HLPR(MajorFunction);
  868. DECLARE_FIELD_HLPR(CurrentIrp);
  869. DECLARE_FIELD_HLPR(pFcb);
  870. DECLARE_FIELD_HLPR(Flags);
  871. DECLARE_FIELD_HLPR(MRxContext);
  872. DECLARE_FIELD_HLPR(MRxCancelRoutine);
  873. DECLARE_FIELD_HLPR(SyncEvent);
  874. DECLARE_FIELD_HLPR(BlockedOperations);
  875. DECLARE_FIELD_HLPR(FlagsForLowIo);
  876. DECLARE_FIELD_HLPR2(Create,CanonicalNameBuffer);
  877. DECLARE_FIELD_HLPR2(Create,pSrvCall);
  878. DECLARE_FIELD_HLPR2(Create,pNetRoot);
  879. DECLARE_FIELD_HLPR2(Create,pVNetRoot);
  880. DECLARE_FIELD_HLPR2(QueryDirectory,FileIndex);
  881. DECLARE_FIELD_HLPR2(QueryEa,UserEaList);
  882. DECLARE_FIELD_HLPR2(QuerySecurity,SecurityInformation);
  883. DECLARE_FIELD_HLPR2(QuerySecurity,Length);
  884. #endif
  885.