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.

437 lines
12 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. cancel.c
  5. Abstract:
  6. This module implements the support for cancelling operations in the RDBSS driver
  7. Author:
  8. Balan Sethu Raman [SethuR] 7-June-95
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_CANCEL)
  17. NTSTATUS
  18. RxSetMinirdrCancelRoutine (
  19. IN OUT PRX_CONTEXT RxContext,
  20. IN PMRX_CALLDOWN MRxCancelRoutine
  21. )
  22. /*++
  23. Routine Description:
  24. The routine sets up a mini rdr cancel routine for an RxContext.
  25. Arguments:
  26. RxContext - the context
  27. MRxCancelRoutine - the cancel routine
  28. Return Value:
  29. None.
  30. Notes:
  31. --*/
  32. {
  33. NTSTATUS Status;
  34. KIRQL SavedIrql;
  35. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  36. if (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED )) {
  37. RxContext->MRxCancelRoutine = MRxCancelRoutine;
  38. Status = STATUS_SUCCESS;
  39. } else {
  40. Status = STATUS_CANCELLED;
  41. }
  42. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  43. return Status;
  44. }
  45. VOID
  46. RxpCancelRoutine (
  47. PRX_CONTEXT RxContext
  48. )
  49. /*++
  50. Routine Description:
  51. This routine is invoked to the underlying mini rdr cancel routine at a non
  52. DPC level. Note: cancel is not generally synchronized with irp completion. So
  53. an irp can complete and cancel can still be called at the same time. The rxcontext is
  54. ref counted so it will stick around. The irp can only be manipulated if some flag in the
  55. rxcontext indicates its still active. This occurs in 2 cases
  56. 1) The irp is in the overflow queue
  57. 2) This is pipe operation that is being synchronized in the blocking queues
  58. Arguments:
  59. RxContext - the context
  60. Return Value:
  61. None.
  62. Notes:
  63. --*/
  64. {
  65. PMRX_CALLDOWN MRxCancelRoutine;
  66. PAGED_CODE();
  67. MRxCancelRoutine = RxContext->MRxCancelRoutine;
  68. if (MRxCancelRoutine != NULL) {
  69. (MRxCancelRoutine)( RxContext );
  70. } else if (!RxCancelOperationInOverflowQueue( RxContext )) {
  71. RxCancelBlockingOperation( RxContext, RxContext->CurrentIrp );
  72. }
  73. RxLog(( "Dec RxC %lx L %ld %lx\n", RxContext, __LINE__, RxContext->ReferenceCount ));
  74. RxWmiLog( LOG,
  75. RxpCancelRoutine,
  76. LOGPTR( RxContext )
  77. LOGULONG( RxContext->ReferenceCount ));
  78. RxDereferenceAndDeleteRxContext( RxContext );
  79. }
  80. VOID
  81. RxCancelRoutine (
  82. IN PDEVICE_OBJECT DeviceObject,
  83. IN PIRP Irp
  84. )
  85. /*++
  86. Routine Description:
  87. The cancel routine for RDBSS
  88. Arguments:
  89. DeviceObject - the device object
  90. Irp - the IRP to be cancelled
  91. Return Value:
  92. None.
  93. Notes:
  94. Any request can be in one of three states in RDBSS ---
  95. 1) the request is being processed.
  96. 2) the request is waiting for the results of a calldown to a minirdr.
  97. 3) the request is waiting on a resource.
  98. Any request that has been accepted by RDBSS ( the corresponding RxContext has been
  99. created and the cancel routine has been set ) is a valid target for cancel. The RDBSS
  100. driver does not make any effort to cancel requests that are in state (1) as described
  101. above.
  102. The cancelling action is invoked on those requests which are either in state (2),
  103. state(3) or when it is about to transition to/from either of these states.
  104. In order to expedite cancelling a similar strategy needs to be in place for the mini
  105. redirectors. This is provided by enabling the mini redirectors to register a cancel routine
  106. and rreserving fields in the RxContext for the mini redirectors to store the state information.
  107. As part of the RDBSS cancel routine the following steps will be taken .....
  108. 1) Locate the RxContext corresponding to the given IRP.
  109. 2) If the RxContext is waiting for a minirdr invoke the appropriate cancel routine.
  110. Note that the request is not immediately completed in all cases. This implies that there
  111. will be latencies in cancelling a request. The goal is to minimise the latency rather
  112. than completely eliminate them.
  113. --*/
  114. {
  115. KIRQL SavedIrql;
  116. PRX_CONTEXT RxContext;
  117. PLIST_ENTRY ListEntry;
  118. //
  119. // Locate the context corresponding to the given Irp.
  120. //
  121. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  122. ListEntry = RxActiveContexts.Flink;
  123. while (ListEntry != &RxActiveContexts) {
  124. RxContext = CONTAINING_RECORD( ListEntry, RX_CONTEXT, ContextListEntry );
  125. if (RxContext->CurrentIrp == Irp) {
  126. break;
  127. } else {
  128. ListEntry = ListEntry->Flink;
  129. }
  130. }
  131. if ((ListEntry != &RxActiveContexts) &&
  132. !FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED )) {
  133. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED );
  134. InterlockedIncrement( &RxContext->ReferenceCount );
  135. } else {
  136. RxContext = NULL;
  137. }
  138. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  139. IoReleaseCancelSpinLock( Irp->CancelIrql );
  140. if (RxContext != NULL) {
  141. if (!RxShouldPostCompletion()) {
  142. RxpCancelRoutine( RxContext );
  143. } else {
  144. RxDispatchToWorkerThread( RxFileSystemDeviceObject,
  145. CriticalWorkQueue,
  146. RxpCancelRoutine,
  147. RxContext );
  148. }
  149. }
  150. }
  151. NTSTATUS
  152. RxCancelNotifyChangeDirectoryRequestsForVNetRoot (
  153. IN PV_NET_ROOT VNetRoot,
  154. IN BOOLEAN ForceFilesClosed
  155. )
  156. /*++
  157. Routine Description:
  158. This routine cancels all the outstanding requests for a given instance of V_NET_ROOT. The
  159. V_NET_ROOT's are created/deleted are independent of the files that are opened/manipulated
  160. in them. Therefore it is imperative that when a delete operation is attempted
  161. all the outstanding requests are cancelled.
  162. Arguments:
  163. VNetRoot - the V_NET_ROOT instance about to be deleted
  164. ForceFilesClosed - if true force close, otherwise fai if opens exist
  165. Return Value:
  166. None.
  167. Notes:
  168. --*/
  169. {
  170. KIRQL SavedIrql;
  171. PRX_CONTEXT RxContext;
  172. PLIST_ENTRY ListEntry;
  173. LIST_ENTRY CancelledContexts;
  174. PMRX_CALLDOWN MRxCancelRoutine;
  175. NTSTATUS Status = STATUS_SUCCESS;
  176. InitializeListHead( &CancelledContexts );
  177. //
  178. // Locate the context corresponding to the given Irp.
  179. //
  180. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  181. ListEntry = RxActiveContexts.Flink;
  182. while (ListEntry != &RxActiveContexts) {
  183. RxContext = CONTAINING_RECORD( ListEntry, RX_CONTEXT, ContextListEntry );
  184. ListEntry = ListEntry->Flink;
  185. if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
  186. (RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) &&
  187. (RxContext->pFcb != NULL) &&
  188. (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED )) &&
  189. (RxContext->NotifyChangeDirectory.pVNetRoot == (PMRX_V_NET_ROOT)VNetRoot) &&
  190. (RxContext->MRxCancelRoutine != NULL)) {
  191. if (!ForceFilesClosed) {
  192. Status = STATUS_FILES_OPEN;
  193. break;
  194. }
  195. //
  196. // After this flag is set no one else will invoke the cancel routine or
  197. // change it
  198. //
  199. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED );
  200. RemoveEntryList( &RxContext->ContextListEntry );
  201. InsertTailList( &CancelledContexts, &RxContext->ContextListEntry );
  202. InterlockedIncrement( &RxContext->ReferenceCount );
  203. }
  204. }
  205. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  206. if (Status == STATUS_SUCCESS) {
  207. while (!IsListEmpty( &CancelledContexts )) {
  208. ListEntry = RemoveHeadList( &CancelledContexts );
  209. InitializeListHead( ListEntry );
  210. RxContext = CONTAINING_RECORD( ListEntry, RX_CONTEXT, ContextListEntry);
  211. //
  212. // check to see if this guy is already completed..........if so, don't call down.
  213. //
  214. if (RxContext->CurrentIrp != NULL) {
  215. MRxCancelRoutine = RxContext->MRxCancelRoutine;
  216. RxContext->MRxCancelRoutine = NULL;
  217. ASSERT( MRxCancelRoutine != NULL );
  218. RxLog(( "CCtx %lx CRtn %lx\n", RxContext, MRxCancelRoutine ));
  219. RxWmiLog( LOG,
  220. RxCancelNotifyChangeDirectoryRequestsForVNetRoot,
  221. LOGPTR( RxContext )
  222. LOGPTR( MRxCancelRoutine ));
  223. (MRxCancelRoutine)( RxContext );
  224. }
  225. RxDereferenceAndDeleteRxContext( RxContext );
  226. }
  227. }
  228. return Status;
  229. }
  230. VOID
  231. RxCancelNotifyChangeDirectoryRequestsForFobx (
  232. PFOBX Fobx
  233. )
  234. /*++
  235. Routine Description:
  236. This routine cancels all the outstanding requests for a given FileObject This
  237. handles the case when a directory handle is closed while it has outstanding
  238. change notify requests pending.
  239. Arguments:
  240. Fobx - the FOBX instance about to be closed
  241. Return Value:
  242. None.
  243. Notes:
  244. --*/
  245. {
  246. KIRQL SavedIrql;
  247. PRX_CONTEXT RxContext;
  248. PLIST_ENTRY ListEntry;
  249. LIST_ENTRY CancelledContexts;
  250. PMRX_CALLDOWN MRxCancelRoutine;
  251. InitializeListHead( &CancelledContexts );
  252. //
  253. // Locate the context corresponding to the given Irp.
  254. //
  255. KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
  256. ListEntry = RxActiveContexts.Flink;
  257. while (ListEntry != &RxActiveContexts) {
  258. RxContext = CONTAINING_RECORD( ListEntry, RX_CONTEXT, ContextListEntry );
  259. ListEntry = ListEntry->Flink;
  260. if ((RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
  261. (RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) &&
  262. (!FlagOn( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED )) &&
  263. (RxContext->pFobx == (PMRX_FOBX)Fobx) &&
  264. (RxContext->MRxCancelRoutine != NULL)) {
  265. //
  266. // After this flag is set no one else will invoke the cancel routine
  267. // or change it
  268. //
  269. SetFlag( RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED );
  270. RemoveEntryList(&RxContext->ContextListEntry);
  271. InsertTailList(&CancelledContexts,&RxContext->ContextListEntry);
  272. InterlockedIncrement(&RxContext->ReferenceCount);
  273. }
  274. }
  275. KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
  276. while (!IsListEmpty(&CancelledContexts )) {
  277. ListEntry = RemoveHeadList(&CancelledContexts);
  278. InitializeListHead( ListEntry );
  279. RxContext = CONTAINING_RECORD( ListEntry, RX_CONTEXT, ContextListEntry );
  280. //
  281. // check to see if this IRP is already completed..........if so,
  282. // don't call down.
  283. //
  284. if (RxContext->CurrentIrp != NULL) {
  285. MRxCancelRoutine = RxContext->MRxCancelRoutine;
  286. RxContext->MRxCancelRoutine = NULL;
  287. ASSERT(MRxCancelRoutine != NULL);
  288. RxLog(( "CCtx %lx CRtn %lx\n", RxContext, MRxCancelRoutine ));
  289. RxWmiLog( LOG,
  290. RxCancelNotifyChangeDirectoryRequestsForFobx,
  291. LOGPTR( RxContext )
  292. LOGPTR( MRxCancelRoutine ));
  293. (MRxCancelRoutine)( RxContext );
  294. }
  295. RxDereferenceAndDeleteRxContext( RxContext );
  296. }
  297. }