The I/O Manager calls a driver-supplied Cancel routine with an input IRP to be cancelled and a DeviceObject pointer representing the target for the request.
Such an IRP might be one that the driver’s DispatchReadWrite routine has queued just as the current Win32 application is being closed by the user. Such an IRP also might be one that a higher-level driver explicitly cancelled, depending on the nature of the underlying device.
When its Cancel routine is called, the input IRP might already be the CurrentIrp in the target device object or might already be in the device queue associated with the target device object if the driver has a StartIo routine. If the driver has no StartIo routine, such a request might be in a driver-managed internal queue of IRPs when its Cancel routine is called. In either case, the I/O Manager resets the Cancel entry point in the incoming IRP to NULL before it calls the Cancel routine with that IRP.
Attempting to complete an IRP while holding a spin lock can cause deadlocks.
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 driver has a StartIo routine.
In such a driver, a Cancel routine usually does the following:
If these pointers are equivalent, the Cancel routine calls ReleaseCancelSpinLock, sets the IRP’s I/O status block with STATUS_CANCELLED for Status and zero for Information, calls IoStartNextPacket, calls IoCompleteRequest with the IRP, and returns control.
Such a driver’s Cancel routine calls KeRemoveEntryDeviceQueue to test whether the IRP is in the device queue because 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.
NT drivers with Cancel routines can handle IRP_MJ_CLEANUP requests as well. For more information about DispatchCleanup routines, see Chapter 6.
The I/O Manager maintains the CurrentIrp field in a device object only if IRPs are queued in the associated device queue object.
If an NT driver manages its own internal queues of IRPs, its Cancel routines can be called with an input IRP that is neither the CurrentIrp for the input target device object nor an IRP in the driver’s internal queue. Such a driver must maintain its own state about which IRP is currently being processed and should have a Cancel routine for each of its queues. Such a driver’s internal queue should be an interlocked queue because its internal queue must be protected by an executive spin lock.
When such a driver’s Cancel routine is called, it usually does the following:
Such a driver usually assumes that I/O processing for the input IRP has already begun if it is not queued.
NT drivers with Cancel routines can handle IRP_MJ_CLEANUP requests as well. For more information about DispatchCleanup routines, see Chapter 6.