for this special exist Remove Locks. read
https://msdn.microsoft.com/en-us/library/windows/hardware/ff565504(v=vs.85).aspx
and
https://msdn.microsoft.com/en-us/library/windows/hardware/ff549567(v=vs.85).aspx
“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.”
interesting that early in documentation was error
“each driver should call IoReleaseRemoveLockAndWait BEFORE it passes the IRP_MN_REMOVE_DEVICE request to the next-lower driver”
really this may hang, if lower DeviceObject have not completed IRPs and complete it only when received IRP_MN_REMOVE_DEVICE
and your driver call IoAcquireRemoveLock on this Irp, set Completion routine and pass this Irp down - you call IoReleaseRemoveLock only when this IRP is complete, but it never complete, because lower DeviceObject never got IRP_MN_REMOVE_DEVICE - if you call IoReleaseRemoveLockAndWait BEFORE
also read this (first reply of Scott Noone)
http://www.osronline.com/showthread.cfm?link=250749
interesting if look for http://www.wd-3.com/031504/AboutRemovalRelations.htm
construction like
98: IoSkipCurrentIrpStackLocation(Irp);
99: status = IoCallDriver(devExt->nextLowerDevice, Irp);
100: IoReleaseRemoveLock(&devExt->RemoveLock, Irp);
incorrect (if Irp was not completed synchronous). IoReleaseRemoveLock need call only from CompletionRoutine and never call IoSkipCurrentIrpStackLocation (except IRP_MN_REMOVE_DEVICE)
and 85-88 lines:
here really need
86: Irp->IoStatus.Status = status:
87: IoSkipCurrentIrpStackLocation(Irp);// only here this is correct
88: status = IoCallDriver(devExt->nextLowerDevice, Irp);
85: IoReleaseRemoveLockAndWait(&devExt->removeLock, Irp); // after !!
89: sendDown = FALSE;
so usual case Filter and FDO deviceses:
// IoReleaseRemoveLockAndWait(&devExt->removeLock, Irp); //not before, can be hang here !!
Irp->IoStatus.Status = status:
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(devExt->nextLowerDevice, Irp);
IoReleaseRemoveLockAndWait(&devExt->removeLock, Irp); // after !!
IoDetachDevice(devExt->nextLowerDevice);
IoDeleteDevice(DeviceObject);
however exist (for my think) else one variant - i always register FastIoDetachDevice and call IoDetachDevice/IoDeleteDevice in this function. so in DispatchPNP i have only this code:
case IRP_MN_REMOVE_DEVICE:
IoSkipCurrentIrpStackLocation(Irp);
return IofCallDriver(devExt->nextLowerDevice, Irp);
and
VOID FastIoDetachDevice(PDEVICE_OBJECT SourceDevice, PDEVICE_OBJECT TargetDevice)
{
DEV_EXTENSION* pExt = DEV_EXTENSION::get(SourceDevice);
IoReleaseRemoveLockAndWait(pExt, 0);
IoDetachDevice(TargetDevice);
IoDeleteDevice(SourceDevice);
}
// FastIoDetachDevice called from IoDeleteDevice for TargetDevice
Your attach call adds a ref to the lower device which is released when you detach
this not exactly true DeviceObject->ReferenceCount is incremented when FileObject created on Device, but not on Attach. however until DeviceObject->AttachedDevice not zero - DeviceObject will be not deleted. so in wide sence this is true