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.
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 processIRP_MN_REMOVE_DEVICE
(after device was not included in the bus driver's most recent response to anIRP_MN_QUERY_DEVICE_RELATIONS
request forBusRelations
- or in another words - whenRemovePending
flag in its device extension)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 checkRemovePending
flag - it yet not set. and you begin process request "as usual". but just after you checkRemovePending
flag inside IO request you can set it while handlingIRP_MN_QUERY_DEVICE_RELATIONS
request withBusRelations
. 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)
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 theIRP_MN_REMOVE_DEVICE
request down to the next driver. but correct must bethis is correct and stated in Using Remove Locks and IoReleaseRemoveLockAndWait. funny that in old msdn versions was
but now this is fixed. why after ? because next-lower driver can pending some IRPs (on which we call
IoAcquireRemoveLock
orExAcquireRundownProtection
) and complete it only when gotIRP_MN_REMOVE_DEVICE
and our driver callIoReleaseRemoveLock
orExReleaseRundownProtection
only when this IRP will be completed. as result if callIoReleaseRemoveLockAndWait
orExWaitForRundownProtectionRelease
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 processIRP_MN_REMOVE_DEVICE
we destroy this resources. what be if we will use some resource in IO request after he will be destroyed inIRP_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 callIoAcquireRemoveLock
orExAcquireRundownProtection
and use it only if ok status returned. after we finish use resource callIoReleaseRemoveLock
orExReleaseRundownProtection
. and inIRP_MN_REMOVE_DEVICE
we callIoReleaseRemoveLockAndWait
orExWaitForRundownProtectionRelease
. after this call is returned - we can be sure that nobody use our resources and never will be used more (calls toIoAcquireRemoveLock
orExAcquireRundownProtection
return error status (false)). at this point we can safe begin destroy resources: releases memory (etc), callsIoDetachDevice
,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 callIoDetachDevice
). really are correct callIofCallDriver(_nextDeviceObject, Irp);
(while process some IO request) after callIoDetachDevice(_nextDeviceObject);
(insideIRP_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 asRemovePending
- so we go to point 4. and after device marked asRemovePending
(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 callIoDeleteDevice