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.

476 lines
11 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. cancelapi.c
  5. Abstract:
  6. This module contains the cancel safe DDI set
  7. Author:
  8. Nar Ganapathy (narg) 1-Jan-1999
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "iomgr.h"
  14. //
  15. // The library exposes everything with the name "Wdmlib". This ensures drivers
  16. // using the backward compatible Cancel DDI Lib won't opportunistically pick
  17. // up the kernel exports just because they were built using the XP DDK.
  18. //
  19. #if CSQLIB
  20. #define CSQLIB_DDI(x) Wdmlib##x
  21. #else
  22. #define CSQLIB_DDI(x) x
  23. #endif
  24. VOID
  25. IopCsqCancelRoutine(
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp
  28. )
  29. /*++
  30. Routine Description:
  31. This routine removes the IRP that's associated with a context from the queue.
  32. It's expected that this routine will be called from a timer or DPC or other threads which complete an
  33. IO. Note that the IRP associated with this context could already have been freed.
  34. Arguments:
  35. Csq - Pointer to the cancel queue.
  36. Context - Context associated with Irp.
  37. Return Value:
  38. Returns the IRP associated with the context. If the value is not NULL, the IRP was successfully
  39. retrieved and can be used safely. If the value is NULL, the IRP was already canceled.
  40. --*/
  41. {
  42. KIRQL irql;
  43. PIO_CSQ_IRP_CONTEXT irpContext;
  44. PIO_CSQ cfq;
  45. UNREFERENCED_PARAMETER (DeviceObject);
  46. IoReleaseCancelSpinLock(Irp->CancelIrql);
  47. irpContext = Irp->Tail.Overlay.DriverContext[3];
  48. if (irpContext->Type == IO_TYPE_CSQ_IRP_CONTEXT) {
  49. cfq = irpContext->Csq;
  50. } else if ((irpContext->Type == IO_TYPE_CSQ) ||
  51. (irpContext->Type == IO_TYPE_CSQ_EX)) {
  52. cfq = (PIO_CSQ)irpContext;
  53. } else {
  54. //
  55. // Bad type
  56. //
  57. ASSERT(0);
  58. return;
  59. }
  60. ASSERT(cfq);
  61. cfq->ReservePointer = NULL; // Force drivers to be good citizens
  62. cfq->CsqAcquireLock(cfq, &irql);
  63. cfq->CsqRemoveIrp(cfq, Irp);
  64. //
  65. // Break the association if necessary.
  66. //
  67. if (irpContext != (PIO_CSQ_IRP_CONTEXT)cfq) {
  68. irpContext->Irp = NULL;
  69. Irp->Tail.Overlay.DriverContext[3] = NULL;
  70. }
  71. cfq->CsqReleaseLock(cfq, irql);
  72. cfq->CsqCompleteCanceledIrp(cfq, Irp);
  73. }
  74. NTSTATUS
  75. CSQLIB_DDI(IoCsqInitialize)(
  76. IN PIO_CSQ Csq,
  77. IN PIO_CSQ_INSERT_IRP CsqInsertIrp,
  78. IN PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
  79. IN PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
  80. IN PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
  81. IN PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
  82. IN PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
  83. )
  84. /*++
  85. Routine Description:
  86. This routine initializes the Cancel queue
  87. Arguments:
  88. Csq - Pointer to the cancel queue.
  89. Return Value:
  90. The function returns STATUS_SUCCESS on successful initialization
  91. --*/
  92. {
  93. Csq->CsqInsertIrp = CsqInsertIrp;
  94. Csq->CsqRemoveIrp = CsqRemoveIrp;
  95. Csq->CsqPeekNextIrp = CsqPeekNextIrp;
  96. Csq->CsqAcquireLock = CsqAcquireLock;
  97. Csq->CsqReleaseLock = CsqReleaseLock;
  98. Csq->CsqCompleteCanceledIrp = CsqCompleteCanceledIrp;
  99. Csq->ReservePointer = NULL;
  100. Csq->Type = IO_TYPE_CSQ;
  101. return STATUS_SUCCESS;
  102. }
  103. NTSTATUS
  104. CSQLIB_DDI(IoCsqInitializeEx)(
  105. IN PIO_CSQ Csq,
  106. IN PIO_CSQ_INSERT_IRP_EX CsqInsertIrp,
  107. IN PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
  108. IN PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
  109. IN PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
  110. IN PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
  111. IN PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
  112. )
  113. /*++
  114. Routine Description:
  115. This routine initializes the Cancel queue
  116. Arguments:
  117. Csq - Pointer to the cancel queue.
  118. Return Value:
  119. The function returns STATUS_SUCCESS on successful initialization
  120. --*/
  121. {
  122. Csq->CsqInsertIrp = (PIO_CSQ_INSERT_IRP)CsqInsertIrp;
  123. Csq->CsqRemoveIrp = CsqRemoveIrp;
  124. Csq->CsqPeekNextIrp = CsqPeekNextIrp;
  125. Csq->CsqAcquireLock = CsqAcquireLock;
  126. Csq->CsqReleaseLock = CsqReleaseLock;
  127. Csq->CsqCompleteCanceledIrp = CsqCompleteCanceledIrp;
  128. Csq->ReservePointer = NULL;
  129. Csq->Type = IO_TYPE_CSQ_EX;
  130. return STATUS_SUCCESS;
  131. }
  132. NTSTATUS
  133. CSQLIB_DDI(IoCsqInsertIrpEx)(
  134. IN PIO_CSQ Csq,
  135. IN PIRP Irp,
  136. IN PIO_CSQ_IRP_CONTEXT Context,
  137. IN PVOID InsertContext
  138. )
  139. /*++
  140. Routine Description:
  141. This routine inserts the IRP into the queue and associates the context with the IRP.
  142. The context has to be in non-paged pool if the context will be used in a DPC or interrupt routine.
  143. The routine assumes that Irp->Tail.Overlay.DriverContext[3] is available for use by the APIs.
  144. It's ok to pass a NULL context if the driver assumes that it will always use IoCsqRemoveNextIrp to
  145. remove an IRP.
  146. Arguments:
  147. Csq - Pointer to the cancel queue.
  148. Irp - Irp to be inserted
  149. Context - Context to be associated with Irp.
  150. InsertContext - Context passed to the driver's insert IRP routine.
  151. Return Value:
  152. NTSTATUS - Status returned by the driver's insert IRP routine. If the driver's insert IRP
  153. routine returns an error status, the IRP is not inserted and the same status is returned
  154. by this API. This allows drivers to implement startIo kind of functionality.
  155. --*/
  156. {
  157. KIRQL irql;
  158. PDRIVER_CANCEL cancelRoutine;
  159. PVOID originalDriverContext;
  160. NTSTATUS status = STATUS_SUCCESS;
  161. //
  162. // Set the association between the context and the IRP.
  163. //
  164. if (Context) {
  165. Irp->Tail.Overlay.DriverContext[3] = Context;
  166. Context->Irp = Irp;
  167. Context->Csq = Csq;
  168. Context->Type = IO_TYPE_CSQ_IRP_CONTEXT;
  169. } else {
  170. Irp->Tail.Overlay.DriverContext[3] = Csq;
  171. }
  172. Csq->ReservePointer = NULL; // Force drivers to be good citizens
  173. originalDriverContext = Irp->Tail.Overlay.DriverContext[3];
  174. Csq->CsqAcquireLock(Csq, &irql);
  175. //
  176. // If the driver wants to fail the insert then do this.
  177. //
  178. if (Csq->Type == IO_TYPE_CSQ_EX) {
  179. PIO_CSQ_INSERT_IRP_EX func;
  180. func = (PIO_CSQ_INSERT_IRP_EX)Csq->CsqInsertIrp;
  181. status = func(Csq, Irp, InsertContext);
  182. if (!NT_SUCCESS(status)) {
  183. Csq->CsqReleaseLock(Csq, irql);
  184. return status;
  185. }
  186. } else {
  187. Csq->CsqInsertIrp(Csq, Irp);
  188. }
  189. IoMarkIrpPending(Irp);
  190. cancelRoutine = IoSetCancelRoutine(Irp, IopCsqCancelRoutine);
  191. ASSERT(!cancelRoutine);
  192. if (Irp->Cancel) {
  193. cancelRoutine = IoSetCancelRoutine(Irp, NULL);
  194. if (cancelRoutine) {
  195. Csq->CsqRemoveIrp(Csq, Irp);
  196. if (Context) {
  197. Context->Irp = NULL;
  198. }
  199. Irp->Tail.Overlay.DriverContext[3] = NULL;
  200. Csq->CsqReleaseLock(Csq, irql);
  201. Csq->CsqCompleteCanceledIrp(Csq, Irp);
  202. } else {
  203. //
  204. // The cancel routine beat us to it.
  205. //
  206. Csq->CsqReleaseLock(Csq, irql);
  207. }
  208. } else {
  209. Csq->CsqReleaseLock(Csq, irql);
  210. }
  211. return status;
  212. }
  213. VOID
  214. CSQLIB_DDI(IoCsqInsertIrp)(
  215. IN PIO_CSQ Csq,
  216. IN PIRP Irp,
  217. IN PIO_CSQ_IRP_CONTEXT Context
  218. )
  219. {
  220. (VOID)CSQLIB_DDI(IoCsqInsertIrpEx)(Csq, Irp, Context, NULL);
  221. }
  222. PIRP
  223. CSQLIB_DDI(IoCsqRemoveNextIrp)(
  224. IN PIO_CSQ Csq,
  225. IN PVOID PeekContext
  226. )
  227. /*++
  228. Routine Description:
  229. This routine removes the next IRP from the queue. This routine will enumerate the queue
  230. and return an IRP that's not canceled. If an IRP in the queue is canceled it goes to the next
  231. IRP. If no IRP is available it returns a NULL. The IRP returned is safe and cannot be canceled.
  232. Arguments:
  233. Csq - Pointer to the cancel queue.
  234. Return Value:
  235. Returns the IRP or NULL.
  236. --*/
  237. {
  238. KIRQL irql;
  239. PIO_CSQ_IRP_CONTEXT context;
  240. PDRIVER_CANCEL cancelRoutine;
  241. PIRP irp;
  242. irp = NULL;
  243. Csq->ReservePointer = NULL; // Force drivers to be good citizens
  244. Csq->CsqAcquireLock(Csq, &irql);
  245. irp = Csq->CsqPeekNextIrp(Csq, NULL, PeekContext);
  246. while (1) {
  247. //
  248. // This routine will return a pointer to the next IRP in the queue adjacent to
  249. // the irp passed as a parameter. If the irp is NULL, it returns the IRP at the head of
  250. // the queue.
  251. //
  252. if (!irp) {
  253. Csq->CsqReleaseLock(Csq, irql);
  254. return NULL;
  255. }
  256. cancelRoutine = IoSetCancelRoutine(irp, NULL);
  257. if (!cancelRoutine) {
  258. irp = Csq->CsqPeekNextIrp(Csq, irp, PeekContext);
  259. continue;
  260. }
  261. Csq->CsqRemoveIrp(Csq, irp); // Remove this IRP from the queue
  262. break;
  263. }
  264. context = irp->Tail.Overlay.DriverContext[3];
  265. if (context->Type == IO_TYPE_CSQ_IRP_CONTEXT) {
  266. context->Irp = NULL;
  267. ASSERT(context->Csq == Csq);
  268. }
  269. irp->Tail.Overlay.DriverContext[3] = NULL;
  270. Csq->CsqReleaseLock(Csq, irql);
  271. return irp;
  272. }
  273. PIRP
  274. CSQLIB_DDI(IoCsqRemoveIrp)(
  275. IN PIO_CSQ Csq,
  276. IN PIO_CSQ_IRP_CONTEXT Context
  277. )
  278. /*++
  279. Routine Description:
  280. This routine removes the IRP that's associated with a context from the queue.
  281. It's expected that this routine will be called from a timer or DPC or other threads which complete an
  282. IO. Note that the IRP associated with this context could already have been freed.
  283. Arguments:
  284. Csq - Pointer to the cancel queue.
  285. Context - Context associated with Irp.
  286. Return Value:
  287. Returns the IRP associated with the context. If the value is not NULL, the IRP was successfully
  288. retrieved and can be used safely. If the value is NULL, the IRP was already canceled.
  289. --*/
  290. {
  291. KIRQL irql;
  292. PIRP irp;
  293. PDRIVER_CANCEL cancelRoutine;
  294. Csq->ReservePointer = NULL; // Force drivers to be good citizens
  295. Csq->CsqAcquireLock(Csq, &irql);
  296. if (Context->Irp ) {
  297. ASSERT(Context->Csq == Csq);
  298. irp = Context->Irp;
  299. cancelRoutine = IoSetCancelRoutine(irp, NULL);
  300. if (!cancelRoutine) {
  301. Csq->CsqReleaseLock(Csq, irql);
  302. return NULL;
  303. }
  304. ASSERT(Context == irp->Tail.Overlay.DriverContext[3]);
  305. Csq->CsqRemoveIrp(Csq, irp);
  306. //
  307. // Break the association.
  308. //
  309. Context->Irp = NULL;
  310. irp->Tail.Overlay.DriverContext[3] = NULL;
  311. ASSERT(Context->Csq == Csq);
  312. Csq->CsqReleaseLock(Csq, irql);
  313. return irp;
  314. } else {
  315. Csq->CsqReleaseLock(Csq, irql);
  316. return NULL;
  317. }
  318. }