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.

918 lines
26 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. complete.c
  5. Abstract:
  6. This module implements the executive I/O completion object. Functions are
  7. provided to create, open, query, and wait for I/O completion objects.
  8. Author:
  9. David N. Cutler (davec) 25-Feb-1994
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. //
  16. // Define forward referenced function prototypes.
  17. //
  18. VOID
  19. IopFreeMiniPacket (
  20. PIOP_MINI_COMPLETION_PACKET MiniPacket
  21. );
  22. //
  23. // Define section types for appropriate functions.
  24. //
  25. #ifdef ALLOC_PRAGMA
  26. #pragma alloc_text(PAGE, NtCreateIoCompletion)
  27. #pragma alloc_text(PAGE, NtOpenIoCompletion)
  28. #pragma alloc_text(PAGE, NtQueryIoCompletion)
  29. #pragma alloc_text(PAGE, NtRemoveIoCompletion)
  30. #pragma alloc_text(PAGE, NtSetIoCompletion)
  31. #pragma alloc_text(PAGE, IoSetIoCompletion)
  32. #pragma alloc_text(PAGE, IopFreeMiniPacket)
  33. #pragma alloc_text(PAGE, IopDeleteIoCompletion)
  34. #endif
  35. NTSTATUS
  36. NtCreateIoCompletion (
  37. IN PHANDLE IoCompletionHandle,
  38. IN ACCESS_MASK DesiredAccess,
  39. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  40. IN ULONG Count OPTIONAL
  41. )
  42. /*++
  43. Routine Description:
  44. This function creates an I/O completion object, sets the maximum
  45. target concurrent thread count to the specified value, and opens
  46. a handle to the object with the specified desired access.
  47. Arguments:
  48. IoCompletionHandle - Supplies a pointer to a variable that receives
  49. the I/O completion object handle.
  50. DesiredAccess - Supplies the desired types of access for the I/O
  51. completion object.
  52. ObjectAttributes - Supplies a pointer to an object attributes structure.
  53. Count - Supplies the target maximum number of threads that should
  54. be concurrently active. If this parameter is not specified, then
  55. the number of processors is used.
  56. Return Value:
  57. STATUS_SUCCESS is returned if the function is success. Otherwise, an
  58. error status is returned.
  59. --*/
  60. {
  61. HANDLE Handle;
  62. KPROCESSOR_MODE PreviousMode;
  63. PVOID IoCompletion;
  64. NTSTATUS Status;
  65. //
  66. // Establish an exception handler, probe the output handle address, and
  67. // attempt to create an I/O completion object. If the probe fails, then
  68. // return the exception code as the service status. Otherwise, return the
  69. // status value returned by the object insertion routine.
  70. //
  71. try {
  72. //
  73. // Get previous processor mode and probe output handle address if
  74. // necessary.
  75. //
  76. PreviousMode = KeGetPreviousMode();
  77. if (PreviousMode != KernelMode) {
  78. ProbeForWriteHandle(IoCompletionHandle);
  79. }
  80. //
  81. // Allocate I/O completion object.
  82. //
  83. Status = ObCreateObject(PreviousMode,
  84. IoCompletionObjectType,
  85. ObjectAttributes,
  86. PreviousMode,
  87. NULL,
  88. sizeof(KQUEUE),
  89. 0,
  90. 0,
  91. (PVOID *)&IoCompletion);
  92. //
  93. // If the I/O completion object was successfully allocated, then
  94. // initialize the object and attempt to insert it in the handle
  95. // table of the current process.
  96. //
  97. if (NT_SUCCESS(Status)) {
  98. KeInitializeQueue((PKQUEUE)IoCompletion, Count);
  99. Status = ObInsertObject(IoCompletion,
  100. NULL,
  101. DesiredAccess,
  102. 0,
  103. (PVOID *)NULL,
  104. &Handle);
  105. //
  106. // If the I/O completion object was successfully inserted in
  107. // the handle table of the current process, then attempt to
  108. // write the handle value. If the write attempt fails, then
  109. // do not report an error. When the caller attempts to access
  110. // the handle value, an access violation will occur.
  111. //
  112. if (NT_SUCCESS(Status)) {
  113. try {
  114. *IoCompletionHandle = Handle;
  115. } except(ExSystemExceptionFilter()) {
  116. NOTHING;
  117. }
  118. }
  119. }
  120. //
  121. // If an exception occurs during the probe of the output handle address,
  122. // then always handle the exception and return the exception code as the
  123. // status value.
  124. //
  125. } except(ExSystemExceptionFilter()) {
  126. Status = GetExceptionCode();
  127. }
  128. //
  129. // Return service status.
  130. //
  131. return Status;
  132. }
  133. NTSTATUS
  134. NtOpenIoCompletion (
  135. OUT PHANDLE IoCompletionHandle,
  136. IN ACCESS_MASK DesiredAccess,
  137. IN POBJECT_ATTRIBUTES ObjectAttributes
  138. )
  139. /*++
  140. Routine Description:
  141. This function opens a handle to an I/O completion object with the
  142. specified desired access.
  143. Arguments:
  144. IoCompletionHandle - Supplies a pointer to a variable that receives
  145. the completion object handle.
  146. DesiredAccess - Supplies the desired types of access for the I/O
  147. completion object.
  148. ObjectAttributes - Supplies a pointer to an object attributes structure.
  149. Return Value:
  150. STATUS_SUCCESS is returned if the function is success. Otherwise, an
  151. error status is returned.
  152. --*/
  153. {
  154. HANDLE Handle;
  155. KPROCESSOR_MODE PreviousMode;
  156. NTSTATUS Status;
  157. //
  158. // Establish an exception handler, probe the output handle address,
  159. // and attempt to open an I/O completion object. If the probe fails,
  160. // then return the exception code as the service status. Otherwise,
  161. // return the status value returned by the object open routine.
  162. //
  163. try {
  164. //
  165. // Get previous processor mode and probe output handle address if
  166. // necessary.
  167. //
  168. PreviousMode = KeGetPreviousMode();
  169. if (PreviousMode != KernelMode) {
  170. ProbeForWriteHandle(IoCompletionHandle);
  171. }
  172. //
  173. // Open handle to the completion object with the specified desired
  174. // access.
  175. //
  176. Status = ObOpenObjectByName(ObjectAttributes,
  177. IoCompletionObjectType,
  178. PreviousMode,
  179. NULL,
  180. DesiredAccess,
  181. NULL,
  182. &Handle);
  183. //
  184. // If the open was successful, then attempt to write the I/O
  185. // completion object handle value. If the write attempt fails,
  186. // then do not report an error. When the caller attempts to
  187. // access the handle value, an access violation will occur.
  188. //
  189. if (NT_SUCCESS(Status)) {
  190. try {
  191. *IoCompletionHandle = Handle;
  192. } except(ExSystemExceptionFilter()) {
  193. NOTHING;
  194. }
  195. }
  196. //
  197. // If an exception occurs during the probe of the output handle address,
  198. // then always handle the exception and return the exception code as the
  199. // status value.
  200. //
  201. } except(ExSystemExceptionFilter()) {
  202. Status = GetExceptionCode();
  203. }
  204. //
  205. // Return service status.
  206. //
  207. return Status;
  208. }
  209. NTSTATUS
  210. NtQueryIoCompletion (
  211. IN HANDLE IoCompletionHandle,
  212. IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
  213. OUT PVOID IoCompletionInformation,
  214. IN ULONG IoCompletionInformationLength,
  215. OUT PULONG ReturnLength OPTIONAL
  216. )
  217. /*++
  218. Routine Description:
  219. This function queries the state of an I/O completion object and returns
  220. the requested information in the specified record structure.
  221. Arguments:
  222. IoCompletionHandle - Supplies a handle to an I/O completion object.
  223. IoCompletionInformationClass - Supplies the class of information being
  224. requested.
  225. IoCompletionInformation - Supplies a pointer to a record that receives
  226. the requested information.
  227. IoCompletionInformationLength - Supplies the length of the record that
  228. receives the requested information.
  229. ReturnLength - Supplies an optional pointer to a variable that receives
  230. the actual length of the information that is returned.
  231. Return Value:
  232. STATUS_SUCCESS is returned if the function is success. Otherwise, an
  233. error status is returned.
  234. --*/
  235. {
  236. PVOID IoCompletion;
  237. LONG Depth;
  238. KPROCESSOR_MODE PreviousMode;
  239. NTSTATUS Status;
  240. //
  241. // Establish an exception handler, probe the output arguments, reference
  242. // the I/O completion object, and return the specified information. If
  243. // the probe fails, then return the exception code as the service status.
  244. // Otherwise return the status value returned by the reference object by
  245. // handle routine.
  246. //
  247. try {
  248. //
  249. // Get previous processor mode and probe output arguments if necessary.
  250. //
  251. PreviousMode = KeGetPreviousMode();
  252. if (PreviousMode != KernelMode) {
  253. ProbeForWriteSmallStructure(IoCompletionInformation,
  254. sizeof(IO_COMPLETION_BASIC_INFORMATION),
  255. sizeof(ULONG));
  256. if (ARGUMENT_PRESENT(ReturnLength)) {
  257. ProbeForWriteUlong(ReturnLength);
  258. }
  259. }
  260. //
  261. // Check argument validity.
  262. //
  263. if (IoCompletionInformationClass != IoCompletionBasicInformation) {
  264. return STATUS_INVALID_INFO_CLASS;
  265. }
  266. if (IoCompletionInformationLength != sizeof(IO_COMPLETION_BASIC_INFORMATION)) {
  267. return STATUS_INFO_LENGTH_MISMATCH;
  268. }
  269. //
  270. // Reference the I/O completion object by handle.
  271. //
  272. Status = ObReferenceObjectByHandle(IoCompletionHandle,
  273. IO_COMPLETION_QUERY_STATE,
  274. IoCompletionObjectType,
  275. PreviousMode,
  276. &IoCompletion,
  277. NULL);
  278. //
  279. // If the reference was successful, then read the current state of
  280. // the I/O completion object, dereference the I/O completion object,
  281. // fill in the information structure, and return the structure length
  282. // if specified. If the write of the I/O completion information or
  283. // the return length fails, then do not report an error. When the
  284. // caller accesses the information structure or length an access
  285. // violation will occur.
  286. //
  287. if (NT_SUCCESS(Status)) {
  288. Depth = KeReadStateQueue((PKQUEUE)IoCompletion);
  289. ObDereferenceObject(IoCompletion);
  290. try {
  291. ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = Depth;
  292. if (ARGUMENT_PRESENT(ReturnLength)) {
  293. *ReturnLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
  294. }
  295. } except(ExSystemExceptionFilter()) {
  296. NOTHING;
  297. }
  298. }
  299. //
  300. // If an exception occurs during the probe of the output arguments, then
  301. // always handle the exception and return the exception code as the status
  302. // value.
  303. //
  304. } except(ExSystemExceptionFilter()) {
  305. Status = GetExceptionCode();
  306. }
  307. //
  308. // Return service status.
  309. //
  310. return Status;
  311. }
  312. NTSTATUS
  313. NtSetIoCompletion (
  314. IN HANDLE IoCompletionHandle,
  315. IN PVOID KeyContext,
  316. IN PVOID ApcContext,
  317. IN NTSTATUS IoStatus,
  318. IN ULONG_PTR IoStatusInformation
  319. )
  320. /*++
  321. Routine Description:
  322. This function allows the caller to queue an Irp to an I/O completion
  323. port and specify all of the information that is returned out the other
  324. end using NtRemoveIoCompletion.
  325. Arguments:
  326. IoCompletionHandle - Supplies a handle to the io completion port
  327. that the caller intends to queue a completion packet to
  328. KeyContext - Supplies the key context that is returned during a call
  329. to NtRemoveIoCompletion
  330. ApcContext - Supplies the apc context that is returned during a call
  331. to NtRemoveIoCompletion
  332. IoStatus - Supplies the IoStatus->Status data that is returned during
  333. a call to NtRemoveIoCompletion
  334. IoStatusInformation - Supplies the IoStatus->Information data that
  335. is returned during a call to NtRemoveIoCompletion
  336. Return Value:
  337. STATUS_SUCCESS is returned if the function is success. Otherwise, an
  338. error status is returned.
  339. --*/
  340. {
  341. PVOID IoCompletion;
  342. NTSTATUS Status;
  343. PAGED_CODE();
  344. Status = ObReferenceObjectByHandle(IoCompletionHandle,
  345. IO_COMPLETION_MODIFY_STATE,
  346. IoCompletionObjectType,
  347. KeGetPreviousMode(),
  348. &IoCompletion,
  349. NULL);
  350. if (NT_SUCCESS(Status)) {
  351. Status = IoSetIoCompletion(IoCompletion,
  352. KeyContext,
  353. ApcContext,
  354. IoStatus,
  355. IoStatusInformation,
  356. TRUE);
  357. ObDereferenceObject(IoCompletion);
  358. }
  359. return Status;
  360. }
  361. NTSTATUS
  362. NtRemoveIoCompletion (
  363. IN HANDLE IoCompletionHandle,
  364. OUT PVOID *KeyContext,
  365. OUT PVOID *ApcContext,
  366. OUT PIO_STATUS_BLOCK IoStatusBlock,
  367. IN PLARGE_INTEGER Timeout OPTIONAL
  368. )
  369. /*++
  370. Routine Description:
  371. This function removes an entry from an I/O completion object. If there
  372. are currently no entries available, then the calling thread waits for
  373. an entry.
  374. Arguments:
  375. Completion - Supplies a handle to an I/O completion object.
  376. KeyContext - Supplies a pointer to a variable that receives the key
  377. context that was specified when the I/O completion object was
  378. assoicated with a file object.
  379. ApcContext - Supplies a pointer to a variable that receives the
  380. context that was specified when the I/O operation was issued.
  381. IoStatus - Supplies a pointer to a variable that receives the
  382. I/O completion status.
  383. Timeout - Supplies a pointer to an optional time out value.
  384. Return Value:
  385. STATUS_SUCCESS is returned if the function is success. Otherwise, an
  386. error status is returned.
  387. --*/
  388. {
  389. PLARGE_INTEGER CapturedTimeout;
  390. PLIST_ENTRY Entry;
  391. PVOID IoCompletion;
  392. PIRP Irp;
  393. KPROCESSOR_MODE PreviousMode;
  394. NTSTATUS Status;
  395. LARGE_INTEGER TimeoutValue;
  396. PVOID LocalApcContext;
  397. PVOID LocalKeyContext;
  398. IO_STATUS_BLOCK LocalIoStatusBlock;
  399. PIOP_MINI_COMPLETION_PACKET MiniPacket;
  400. //
  401. // Establish an exception handler, probe the I/O context, the I/O
  402. // status, and the optional timeout value if specified, reference
  403. // the I/O completion object, and attempt to remove an entry from
  404. // the I/O completion object. If the probe fails, then return the
  405. // exception code as the service status. Otherwise, return a value
  406. // dependent on the outcome of the queue removal.
  407. //
  408. try {
  409. //
  410. // Get previous processor mode and probe the I/O context, status,
  411. // and timeout if necessary.
  412. //
  413. CapturedTimeout = NULL;
  414. PreviousMode = KeGetPreviousMode();
  415. if (PreviousMode != KernelMode) {
  416. ProbeForWriteUlong_ptr((PULONG_PTR)ApcContext);
  417. ProbeForWriteUlong_ptr((PULONG_PTR)KeyContext);
  418. ProbeForWriteIoStatus(IoStatusBlock);
  419. if (ARGUMENT_PRESENT(Timeout)) {
  420. CapturedTimeout = &TimeoutValue;
  421. TimeoutValue = ProbeAndReadLargeInteger(Timeout);
  422. }
  423. } else{
  424. if (ARGUMENT_PRESENT(Timeout)) {
  425. CapturedTimeout = Timeout;
  426. }
  427. }
  428. //
  429. // Reference the I/O completion object by handle.
  430. //
  431. Status = ObReferenceObjectByHandle(IoCompletionHandle,
  432. IO_COMPLETION_MODIFY_STATE,
  433. IoCompletionObjectType,
  434. PreviousMode,
  435. &IoCompletion,
  436. NULL);
  437. //
  438. // If the reference was successful, then attempt to remove an entry
  439. // from the I/O completion object. If an entry is removed from the
  440. // I/O completion object, then capture the completion information,
  441. // release the associated IRP, and attempt to write the completion
  442. // inforamtion. If the write of the completion infomation fails,
  443. // then do not report an error. When the caller attempts to access
  444. // the completion information, an access violation will occur.
  445. //
  446. if (NT_SUCCESS(Status)) {
  447. Entry = KeRemoveQueue((PKQUEUE)IoCompletion,
  448. PreviousMode,
  449. CapturedTimeout);
  450. //
  451. // N.B. The entry value returned can be the address of a list
  452. // entry, STATUS_USER_APC, or STATUS_TIMEOUT.
  453. //
  454. if (((LONG_PTR)Entry == STATUS_TIMEOUT) ||
  455. ((LONG_PTR)Entry == STATUS_USER_APC)) {
  456. Status = (NTSTATUS)((LONG_PTR)Entry);
  457. } else {
  458. //
  459. // Set the completion status, capture the completion
  460. // information, deallocate the associated IRP, and
  461. // attempt to write the completion information.
  462. //
  463. Status = STATUS_SUCCESS;
  464. try {
  465. MiniPacket = CONTAINING_RECORD(Entry,
  466. IOP_MINI_COMPLETION_PACKET,
  467. ListEntry);
  468. if ( MiniPacket->PacketType == IopCompletionPacketIrp ) {
  469. Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
  470. LocalApcContext = Irp->Overlay.AsynchronousParameters.UserApcContext;
  471. LocalKeyContext = (PVOID)Irp->Tail.CompletionKey;
  472. LocalIoStatusBlock = Irp->IoStatus;
  473. IoFreeIrp(Irp);
  474. } else {
  475. LocalApcContext = MiniPacket->ApcContext;
  476. LocalKeyContext = (PVOID)MiniPacket->KeyContext;
  477. LocalIoStatusBlock.Status = MiniPacket->IoStatus;
  478. LocalIoStatusBlock.Information = MiniPacket->IoStatusInformation;
  479. IopFreeMiniPacket(MiniPacket);
  480. }
  481. *ApcContext = LocalApcContext;
  482. *KeyContext = LocalKeyContext;
  483. *IoStatusBlock = LocalIoStatusBlock;
  484. } except(ExSystemExceptionFilter()) {
  485. NOTHING;
  486. }
  487. }
  488. //
  489. // Deference I/O completion object.
  490. //
  491. ObDereferenceObject(IoCompletion);
  492. }
  493. //
  494. // If an exception occurs during the probe of the previous count, then
  495. // always handle the exception and return the exception code as the status
  496. // value.
  497. //
  498. } except(ExSystemExceptionFilter()) {
  499. Status = GetExceptionCode();
  500. }
  501. //
  502. // Return service status.
  503. //
  504. return Status;
  505. }
  506. NTKERNELAPI
  507. NTSTATUS
  508. IoSetIoCompletion (
  509. IN PVOID IoCompletion,
  510. IN PVOID KeyContext,
  511. IN PVOID ApcContext,
  512. IN NTSTATUS IoStatus,
  513. IN ULONG_PTR IoStatusInformation,
  514. IN BOOLEAN Quota
  515. )
  516. /*++
  517. Routine Description:
  518. This function allows the caller to queue an Irp to an I/O completion
  519. port and specify all of the information that is returned out the other
  520. end using NtRemoveIoCompletion.
  521. Arguments:
  522. IoCompletion - Supplies a a pointer to the completion port that the caller
  523. intends to queue a completion packet to.
  524. KeyContext - Supplies the key context that is returned during a call
  525. to NtRemoveIoCompletion.
  526. ApcContext - Supplies the apc context that is returned during a call
  527. to NtRemoveIoCompletion.
  528. IoStatus - Supplies the IoStatus->Status data that is returned during
  529. a call to NtRemoveIoCompletion.
  530. IoStatusInformation - Supplies the IoStatus->Information data that
  531. is returned during a call to NtRemoveIoCompletion.
  532. Return Value:
  533. STATUS_SUCCESS is returned if the function is success. Otherwise, an
  534. error status is returned.
  535. --*/
  536. {
  537. PGENERAL_LOOKASIDE Lookaside;
  538. PIOP_MINI_COMPLETION_PACKET MiniPacket;
  539. ULONG PacketType;
  540. PKPRCB Prcb;
  541. NTSTATUS Status = STATUS_SUCCESS;
  542. PAGED_CODE();
  543. //
  544. // Attempt to allocate the minpacket from the per processor lookaside list.
  545. //
  546. PacketType = IopCompletionPacketMini;
  547. Prcb = KeGetCurrentPrcb();
  548. Lookaside = Prcb->PPLookasideList[LookasideCompletionList].P;
  549. Lookaside->TotalAllocates += 1;
  550. MiniPacket = (PVOID)InterlockedPopEntrySList(&Lookaside->ListHead);
  551. //
  552. // If the per processor lookaside list allocation failed, then attempt to
  553. // allocate from the system lookaside list.
  554. //
  555. if (MiniPacket == NULL) {
  556. Lookaside->AllocateMisses += 1;
  557. Lookaside = Prcb->PPLookasideList[LookasideCompletionList].L;
  558. Lookaside->TotalAllocates += 1;
  559. MiniPacket = (PVOID)InterlockedPopEntrySList(&Lookaside->ListHead);
  560. }
  561. //
  562. // If both lookaside allocation attempts failed, then attempt to allocate
  563. // from pool.
  564. //
  565. if (MiniPacket == NULL) {
  566. Lookaside->AllocateMisses += 1;
  567. //
  568. // If quota is specified, then allocate pool with quota charged.
  569. // Otherwise, allocate pool without quota.
  570. //
  571. if (Quota != FALSE) {
  572. PacketType = IopCompletionPacketQuota;
  573. try {
  574. MiniPacket = ExAllocatePoolWithQuotaTag(NonPagedPool,
  575. sizeof(*MiniPacket),
  576. ' pcI');
  577. } except(EXCEPTION_EXECUTE_HANDLER) {
  578. NOTHING;
  579. }
  580. } else {
  581. MiniPacket = ExAllocatePoolWithTagPriority(NonPagedPool,
  582. sizeof(*MiniPacket),
  583. ' pcI',
  584. LowPoolPriority);
  585. }
  586. }
  587. //
  588. // If a minipacket was successfully allocated, then initialize and
  589. // queue the packet to the specified I/O completion queue.
  590. //
  591. if (MiniPacket != NULL) {
  592. MiniPacket->PacketType = PacketType;
  593. MiniPacket->KeyContext = KeyContext;
  594. MiniPacket->ApcContext = ApcContext;
  595. MiniPacket->IoStatus = IoStatus;
  596. MiniPacket->IoStatusInformation = IoStatusInformation;
  597. KeInsertQueue((PKQUEUE)IoCompletion, &MiniPacket->ListEntry);
  598. } else {
  599. Status = STATUS_INSUFFICIENT_RESOURCES;
  600. }
  601. return Status;
  602. }
  603. VOID
  604. IopFreeMiniPacket (
  605. PIOP_MINI_COMPLETION_PACKET MiniPacket
  606. )
  607. /*++
  608. Routine Description:
  609. This function free the specefied I/O completion packet.
  610. Arguments:
  611. MiniPacket - Supplies a pointer to an I/O completion minipacket.
  612. Return Value:
  613. None.
  614. --*/
  615. {
  616. PGENERAL_LOOKASIDE Lookaside;
  617. PKPRCB Prcb;
  618. //
  619. // If the minipacket cannot be returned to either the per processor or
  620. // system lookaside list, then free the minipacket to pool. Otherwise,
  621. // release the quota if quota was allocated and push the entry onto
  622. // one of the lookaside lists.
  623. //
  624. Prcb = KeGetCurrentPrcb();
  625. Lookaside = Prcb->PPLookasideList[LookasideCompletionList].P;
  626. Lookaside->TotalFrees += 1;
  627. if (ExQueryDepthSList(&Lookaside->ListHead) >= Lookaside->Depth) {
  628. Lookaside->FreeMisses += 1;
  629. Lookaside = Prcb->PPLookasideList[LookasideCompletionList].L;
  630. Lookaside->TotalFrees += 1;
  631. if (ExQueryDepthSList(&Lookaside->ListHead) >= Lookaside->Depth) {
  632. Lookaside->FreeMisses += 1;
  633. ExFreePool(MiniPacket);
  634. } else {
  635. if (MiniPacket->PacketType == IopCompletionPacketQuota) {
  636. ExReturnPoolQuota(MiniPacket);
  637. }
  638. InterlockedPushEntrySList(&Lookaside->ListHead,
  639. (PSINGLE_LIST_ENTRY)MiniPacket);
  640. }
  641. } else {
  642. if (MiniPacket->PacketType == IopCompletionPacketQuota) {
  643. ExReturnPoolQuota(MiniPacket);
  644. }
  645. InterlockedPushEntrySList(&Lookaside->ListHead,
  646. (PSINGLE_LIST_ENTRY)MiniPacket);
  647. }
  648. return;
  649. }
  650. VOID
  651. IopDeleteIoCompletion (
  652. IN PVOID Object
  653. )
  654. /*++
  655. Routine Description:
  656. This function is the delete routine for I/O completion objects. Its
  657. function is to release all the entries in the repsective completion
  658. queue and to rundown all threads that are current associated.
  659. Arguments:
  660. Object - Supplies a pointer to an executive I/O completion object.
  661. Return Value:
  662. None.
  663. --*/
  664. {
  665. PLIST_ENTRY FirstEntry;
  666. PIRP Irp;
  667. PLIST_ENTRY NextEntry;
  668. PIOP_MINI_COMPLETION_PACKET MiniPacket;
  669. //
  670. // Rundown threads associated with the I/O completion object and get
  671. // the list of unprocessed I/O completion IRPs.
  672. //
  673. FirstEntry = KeRundownQueue((PKQUEUE)Object);
  674. if (FirstEntry != NULL) {
  675. NextEntry = FirstEntry;
  676. do {
  677. MiniPacket = CONTAINING_RECORD(NextEntry,
  678. IOP_MINI_COMPLETION_PACKET,
  679. ListEntry);
  680. NextEntry = NextEntry->Flink;
  681. if (MiniPacket->PacketType == IopCompletionPacketIrp) {
  682. Irp = CONTAINING_RECORD(MiniPacket, IRP, Tail.Overlay.ListEntry);
  683. IoFreeIrp(Irp);
  684. } else {
  685. IopFreeMiniPacket(MiniPacket);
  686. }
  687. } while (FirstEntry != NextEntry);
  688. }
  689. return;
  690. }