Any NT driver in which IRPs can be held for an indefinite interval should have a DispatchCleanup routine. If IRPs might be queued when a user-mode handle for a file object that represents the underlying physical or logical device is closed, the highest-level driver holding IRPs bound for that device must have a DispatchCleanup routine.
An NT driver’s DispatchCleanup routine is called to cancel all IRPs that are currently queued to the target device object for the file object specified in the driver’s I/O stack location of the cleanup IRP.
In general, a DispatchCleanup routine must do the following:
The DispatchCleanup routine must set up the I/O status block as follows in each IRP queued to the target device object for the given file object, before it completes each IRP to be cancelled:
Status |
set to STATUS_CANCELLED |
Information |
set to zero |
The DispatchCleanup routine specifies IO_NO_INCREMENT when it calls IoCompleteRequest with each cancelled IRP. After it has cancelled all queued IRPs for the given file object, the DispatchCleanup routine completes the cleanup request itself with STATUS_SUCCESS and a PriorityBoost of IO_NO_INCREMENT.
If a driver manages its own internal queue of IRPs, rather than using the device queue associated with its device object, the driver should set up an interlocked queue that is protected with an executive spin lock. Otherwise, another driver routine (running on another processor in an SMP machine) might dequeue an IRP that should be cancelled by the DispatchCleanup routine. To remove an IRP from such a queue and cancel it, the DispatchCleanup routine calls an ExInterlocked..List support routine with a driver-supplied executive spin lock.
Any area in the device extension of the target device object that is shared between the DispatchCleanup routine and another driver routine also must be protected by a spin lock.
Any NT driver must synchronize its access to cancelable IRPs with the I/O Manager and with its own Cancel routine(s), if any.
Consider the following guidelines for managing spin lock usage within a DispatchCleanup routine that must synchronize with one or more Cancel routines:
Such a DispatchCleanup routine must release any nested spin lock acquisitions in inverse order: that is, it must release its own spin lock(s) before it calls IoReleaseCancelSpinLock.
If a driver manages its own queue(s) of IRPs, then the DispatchCleanup routine does not need to acquire the cancel spin lock before calling IoSetCancelRoutine.
For more information about Cancel routines, see also Chapter 12.
Keep the following points in mind when implementing a DispatchCleanup routine: