Cancel Routines in Drivers with StartIo Routines

The I/O manager maintains the CurrentIrp field in a device object only if IRPs are queued in the associated device queue object. That is, the field is valid only if the driver has a StartIo routine.

In a driver that has a StartIo routine, a typical Cancel routine must do the following:

  1. Check whether the pointer for the input IRP matches the target device object's CurrentIrp address.

    If these pointers are equivalent, the Cancel routine calls IoReleaseCancelSpinLock, passing Irp->CancelIrql, and returns control.

  2. If the canceled IRP is not the current IRP, check whether the input canceled IRP is in the device queue associated with the target device object by calling KeRemoveEntryDeviceQueue with the IRP's Tail.Overlay.DeviceQueueEntry pointer.

    • If the IRP is in the device queue, calling KeRemoveEntryDeviceQueue removes it from the queue. The Cancel routine calls IoReleaseCancelSpinLock, sets the IRP's I/O status block with STATUS_CANCELLED for Status and zero for Information, calls IoCompleteRequest with the canceled IRP, and returns control.

    • If the IRP is not in the device queue, the Cancel routine calls IoReleaseCancelSpinLock and returns control.

The driver's Cancel routine should call KeRemoveEntryDeviceQueue to test whether the IRP is in the device queue. This support routine either removes the given IRP from the device queue or does nothing except return FALSE, indicating that the given entry was not queued. A Cancel routine cannot assume that the input IRP is at any particular position in the device queue, so it cannot call KeRemoveDeviceQueue or KeRemoveByKeyDeviceQueue to compare the pointers to the returned IRP and input IRP.

Drivers with Cancel routines can handle IRP_MJ_CLEANUP requests as well. See DispatchCleanup for more information about IRP_MJ_CLEANUP requests.