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.

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