If an NT driver handles cancelable IRPs, it is responsible for setting the appropriate Cancel routine in each IRP that will be put into a cancelable state as it is processed in stages by the driver’s routines.
The following summarizes guidelines for driver routines that handle cancelable IRPs.
If a device driver has a StartIo routine, its Dispatch routines must specify a driver-supplied Cancel routine’s entry point when they call IoStartPacket.
Otherwise, any driver’s Dispatch routine(s) must do the following before queueing an IRP for further processing by other driver routines:
1. Call IoAcquireCancelSpinLock.
In a similar manner, any routine in such a driver that passes an IRP on for further processing by other routines in the same driver should set up a Cancel routine if that request could be held in a cancelable state before another driver routine begins processing it.
Drivers that manage their own queue(s) of IRPs, rather than using the I/O-manager-supplied device queue, do not need to acquire the cancel spin lock when calling IoSetCancelRoutine.
A driver’s StartIo routine, if any, and/or any other routine that dequeues or is called with an IRP that was held in a cancelable state must do the following:
1. Call IoSetCancelRoutine with a NULL CancelRoutine pointer to remove the IRP from the cancelable state.
2. Call IoReleaseCancelSpinLock.
3. Start the requested device I/O operation for the target device object or, from a higher-level driver, pass the request on to lower drivers.
Any other driver routine that dequeues an IRP or is called with an IRP that might have been held pending for an indefinite interval should do likewise. That is, such a routine must test whether the IRP should be cancelled or remove the IRP from the cancelable state before it begins I/O processing for that IRP.
Drivers that manage their own queue(s) of IRPs, rather than using the I/O-manager-supplied device queue, do not need to acquire the cancel spin lock when calling IoSetCancelRoutine.
In any driver that handles cancelable IRPs, every driver routine that processes an IRP before the underlying device has been programmed for the requested I/O operation should check the cancelable state of all incoming IRPs. That is, a highest-level NT device driver with both StartIo and ControllerControl routines should process incoming IRPs in both these driver routines as already described.
This ensures that only the caller can change the cancelable state of that IRP for the following reasons:
Attempting to complete an IRP while holding a spin lock can cause deadlocks.