WDM device removal in PnP driver

977 views Asked by At

I have question about device removal.

When we want to notify PnP manager that device has disappeared we call IoInvalidateDeviceRelations with BusRelations. After that OS will send IRP_MN_QUERY_DEVICE_RELATIONS request with BusRelations. In this request handler we will exclude device from array and will do another necessary job to "disconnect" it from bus, also we will set RemovePending flag in its device extension.

I don't understand how to deal with incoming IO requests to the device after it becomes "remove pending" and before OS sends IRP_MN_REMOVE_DEVICE request. Should we check RemovePending flag and return STATUS_DEVICE_DOES_NOT_EXIST or should we proceed as usual?

Now imagine that IRP_MN_REMOVE_DEVICE request has finally arrived. MSDN says that we must call IoReleaseRemoveLockAndWait that releases the current acquisition of remove lock, prevents subsequent acquisitions and waits while existing acquisitions are released. So it forces us to always acquire remove lock inside PnP request handler with IoAcquireRemoveLock; and release it with IoReleaseRemoveLockAndWait for IRP_MN_REMOVE_DEVICE or with IoReleaseRemoveLock for another minor codes.

I don't understand why we need to acquire remove lock inside PnP request handler? In my understanding we need to acquire remove lock only for pending irp and release it when such irp is completed. So Windows folks could provide us with IoWaitForExistingRemoveLocks routine instead of IoReleaseRemoveLockAndWait.

Sorry if it's kinda messy, I just can't figure it out. Thanks.

1

There are 1 answers

15
RbMm On BEST ANSWER

After that OS will send IRP_MN_QUERY_DEVICE_RELATIONS request with BusRelations. In this request handler we will exclude device from array and will do another necessary job to "disconnect" it from bus, also we will set RemovePending flag in its device extension.

here need only exclude device from array and set RemovePending flag in its device extension. but do another necessary job to "disconnect" it from bus - need do only when you process IRP_MN_REMOVE_DEVICE (after device was not included in the bus driver's most recent response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations - or in another words - when RemovePending flag in its device extension)

how to deal with incoming IO requests to the device after it becomes "remove pending" and before OS sends IRP_MN_REMOVE_DEVICE request. Should we check RemovePending flag and return STATUS_DEVICE_DOES_NOT_EXIST or should we proceed as usual?

i think possible both behavior - you can process it as usual and can return STATUS_DEVICE_DOES_NOT_EXIST too. and assume next situation - you get some IO request in concurrent with removal device process. when you check RemovePending flag - it yet not set. and you begin process request "as usual". but just after you check RemovePending flag inside IO request you can set it while handling IRP_MN_QUERY_DEVICE_RELATIONS request with BusRelations. and this situation direct related to sense using Remove Locks or Run-Down Protection.

we really can use Run-Down Protection instead Remove Locks almost in same way and exactly in same places and for same reason as Remove Locks. and i think Run-Down Protection api (more new compare remove locks) - better design and better for use (however different is minimal)

I don't understand why we need to acquire remove lock inside PnP request handler?

first of all note that about remove lock said only in Removing a Device in a Function Driver. you how i understand have not function, but bus driver- so Removing a Device in a Bus Driver more suitable for you. and in documentation for Removing a Device in a Function Driver exist serious error - advice first call IoReleaseRemoveLockAndWait at point 4 - before point 8 - Pass the IRP_MN_REMOVE_DEVICE request down to the next driver. but correct must be

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.

this is correct and stated in Using Remove Locks and IoReleaseRemoveLockAndWait. funny that in old msdn versions was

call IoReleaseRemoveLockAndWait before it passes..

but now this is fixed. why after ? because next-lower driver can pending some IRPs (on which we call IoAcquireRemoveLock or ExAcquireRundownProtection) and complete it only when got IRP_MN_REMOVE_DEVICE and our driver call IoReleaseRemoveLock or ExReleaseRundownProtection only when this IRP will be completed. as result if call IoReleaseRemoveLockAndWait or ExWaitForRundownProtectionRelease before passes the remove IRP to the next-lower driver - we can wait here forever - next-lower driver can not complete some IRP (until not got remove request) and we not release remove lock or rundown protection.

so for what we need remove locks or rundown protection ? because we can got IRP_MN_REMOVE_DEVICE in concurrent with another IO requests. and this IO requests can use some resources on device. from another sized when we process IRP_MN_REMOVE_DEVICE we destroy this resources. what be if we will use some resource in IO request after he will be destroyed in IRP_MN_REMOVE_DEVICE ? think not need answer. for prevent this and exist removal locks or rundown protection. before use any resource (which will be destroyed in remove) need call IoAcquireRemoveLock or ExAcquireRundownProtection and use it only if ok status returned. after we finish use resource call IoReleaseRemoveLock or ExReleaseRundownProtection. and in IRP_MN_REMOVE_DEVICE we call IoReleaseRemoveLockAndWait or ExWaitForRundownProtectionRelease. after this call is returned - we can be sure that nobody use our resources and never will be used more (calls to IoAcquireRemoveLock or ExAcquireRundownProtection return error status (false)). at this point we can safe begin destroy resources: releases memory (etc), calls IoDetachDevice, IoDeleteDevice.

the pointer to the next-lower device - this is also resource, which we use in process IO request and destroy in IRP_MN_REMOVE_DEVICE (by call IoDetachDevice). really are correct call IofCallDriver(_nextDeviceObject, Irp); (while process some IO request) after call IoDetachDevice(_nextDeviceObject); (inside IRP_MN_REMOVE_DEVICE) ? because this removal locks (or i use yourself rundown-protection here ) always used in functions and filter drivers. for bus driver, where we usually have not pointer to the next-lower device (PDO not attached to another device, when FDO attached to PDO and filter always attached to something) - may be not need locks (or rundown protection at all). this is depend - are exist another resources - used and destroyed (on removal).

and for bus devices - usual situation when we got IRP_MN_REMOVE_DEVICE 2 time - first before device marked as RemovePending - so we go to point 4. and after device marked as RemovePending (so device was not included in the bus driver's most recent response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations) we finally destroy resources and call IoDeleteDevice