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.
After that OS will send
IRP_MN_QUERY_DEVICE_RELATIONS
request withBusRelations
. In this request handler we will exclude device from array and will do another necessary job to "disconnect" it from bus, also we will setRemovePending
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 checkRemovePending
flag and returnSTATUS_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 theIRP_MN_REMOVE_DEVICE
request to the next-lower driver, and before it releases memory, callsIoDetachDevice
, or callsIoDeleteDevice
.
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