Using Remove Locks
The remove lock routines provide a way to track the number of outstanding I/O operations on a device, and to determine when it is safe to detach and delete a driver's device object. The system provides these routines to driver writers as an alternative to implementing their own tracking mechanism.
A driver can use this mechanism for two purposes:
To ensure that the driver's DispatchPnP routine will not complete an IRP_MN_REMOVE_DEVICE request while the lock is held (for example, while another driver routine is accessing the device).
To count the number of reasons why the driver should not delete its device object, and to set an event when that count goes to zero.
To initialize a remove lock, a driver should allocate an IO_REMOVE_LOCK structure in its device extension and then call IoInitializeRemoveLock. A driver typically calls IoInitializeRemoveLock in its AddDevice routine, when the driver initializes the rest of the device extension for a device object.
Your driver must call IoAcquireRemoveLock each time it starts an I/O operation. The driver must call IoReleaseRemoveLock each time it finishes an I/O operation. A driver can acquire the lock more than once. The remove lock routines maintain a count of the outstanding acquisitions of the lock. Each call to IoAcquireRemoveLock increments the count, and IoReleaseRemoveLock decrements the count.
Your driver should also call IoAcquireRemoveLock when it passes out a reference to its code (for timers, DPCs, callbacks, and so on). The driver then must call IoReleaseRemoveLock when the event has returned.
In its dispatch code for IRP_MN_REMOVE_DEVICE, the driver must acquire the lock once more and then call IoReleaseRemoveLockAndWait. This routine does not return until all outstanding acquisitions of the lock have been released. To allow queued I/O operations to complete, each driver should call IoReleaseRemoveLockAndWait after it passes the IRP_MN_REMOVE_DEVICE request to the next-lower driver, and before it releases memory, calls IoDetachDevice, or calls IoDeleteDevice. After IoReleaseRemoveLockAndWait has been called for a particular remove lock, all subsequent calls to IoAcquireRemoveLock for the same remove lock will fail.
After IoReleaseRemoveLockAndWait returns, the driver should consider the device to be in a state in which it is ready to be removed and cannot perform I/O operations. Therefore, the driver must not call IoInitializeRemoveLock to re-initialize the remove lock. Violation of this rule while the driver is being verified by Driver Verifier will result in a bug check.
Because a driver stores an IO_REMOVE_LOCK structure in the device extension of a device object, the remove lock is deleted when the driver deletes the device extension while processing an IRP_MN_REMOVE_DEVICE request.