Windows PnP驱动程序中WDM设备的删除

Windows PnP驱动程序中WDM设备的删除,windows,driver,wdm,plug-and-play,Windows,Driver,Wdm,Plug And Play,我对移除设备有疑问 当我们想要通知PnP管理器设备已消失时,我们调用IoInvalidateDeviceRelations with BusRelations。之后,操作系统将发送IRP\u MN\u QUERY\u DEVICE\u RELATIONS请求和BusRelations。在这个请求处理程序中,我们将从阵列中排除设备,并将执行另一项必要的工作以断开它与总线的连接,我们还将在其设备扩展中设置RemovePending标志 我不明白在设备处于删除挂起状态之后,操作系统发送IRP\u MN

我对移除设备有疑问

当我们想要通知PnP管理器设备已消失时,我们调用IoInvalidateDeviceRelations with BusRelations。之后,操作系统将发送IRP\u MN\u QUERY\u DEVICE\u RELATIONS请求和BusRelations。在这个请求处理程序中,我们将从阵列中排除设备,并将执行另一项必要的工作以断开它与总线的连接,我们还将在其设备扩展中设置RemovePending标志

我不明白在设备处于删除挂起状态之后,操作系统发送IRP\u MN\u remove\u设备请求之前,如何处理传入的IO请求。我们应该检查RemovePending标志并返回状态\u设备\u不存在\u还是照常进行

现在想象一下,IRP\u MN\u REMOVE\u设备请求终于到达了。MSDN说,我们必须调用IOreleaseRemovelock和Wait来释放当前的remove lock采集,防止后续采集,并在现有采集被释放时等待。因此,它迫使我们始终使用IOAcquisitioneMovelock获取PnP请求处理程序中的remove锁;然后使用IoReleaseRemoveLock释放它,等待IRP_MN_REMOVE_设备,或使用IoReleaseRemoveLock释放另一个次要代码

我不明白为什么我们需要获取PnP请求处理程序中的移除锁?据我所知,我们只需要为挂起的irp获取移除锁,并在该irp完成时释放它。所以Windows用户可以为我们提供IoWaitForExistingRemoveLocks例程,而不是IOReleaseRemovelock和Wait

对不起,如果有点乱,我就是想不出来。谢谢

之后,操作系统将发送IRP\u MN\u查询\u设备\u关系请求 巴士关系。在此请求处理程序中,我们将从 阵列,并将执行另一项必要的工作,将其与总线断开, 我们还将在其设备扩展中设置RemovePending标志

这里只需要从数组中排除设备,并在其设备扩展中设置RemovePending标志。但是,要做另一项必要的工作来断开它与总线的连接—只需要在总线驱动程序最近对总线关系的IRP_mnu查询_设备_关系请求的响应中没有包含一个设备之后处理IRP_mnu_REMOVE_DEVICE,或者换句话说,在其设备扩展中的RemovePending标志时才需要这样做

如何处理设备发生故障后传入的IO请求 在操作系统发送IRP\u MN\u remove\u设备请求之前删除挂起的设备。 我们应该检查RemovePending标志并返回吗 状态设备不存在,或者我们应该照常进行吗

我认为这两种行为都是可能的——你可以像往常一样处理它,并且可以返回设备不存在的状态。假设下一种情况——在删除设备的过程中,您会收到一些IO请求。当您选中RemovePending标志时,它尚未设置。然后像往常一样开始处理请求。但在检查IO请求中的RemovePending标志之后,您可以在使用BusRelations处理IRP\u MN\u QUERY\u DEVICE\u RELATIONS请求时设置它。而这种情况直接关系到感官的使用或使用

我们真的可以使用破旧的保护,而不是删除锁几乎以同样的方式,完全在相同的地方,出于相同的原因删除锁。而且我认为运行中的保护api比移除锁更新-更好的设计和更好的使用,但是差异最小

我不明白为什么我们需要获得解除PnP内的锁 请求处理程序

首先要注意的是,关于拆锁只说在。你怎么知道我没有功能,但公交车司机-所以更适合你。在exist严重错误的文档中,建议在第4点第一次调用,在第8点之前,将IRP_MN_REMOVE_设备请求传递给下一个驱动程序。但必须是正确的

驱动程序应调用IOreleaseRemovelock并在其通过后等待 IRP_MN_REMOVE_设备请求发送给下一个较低的驱动器,以及 在释放内存之前,调用IoDetachDevice或调用 碘电解装置

这是正确的,并在和中说明。有趣的是,在旧的msdn版本中

调用ioreleaseremovelock并等待它通过

但现在这是固定的。为什么之后?因为下一个较低的驱动程序可以挂起一些IRP,在这些IRP上我们称之为IoAcquireRemoveLock或ExAcquireRemownProtection,并且只有在获得IRP\u MN\u REMOVE\u设备时才完成它,而我们的驱动程序只有在完成此IRP时才调用IoReleaseRemoveLock或ExReleaseRundownProtection。因此,如果调用IOreleaseRemovelock和wait或ExWaitForRundownProtectionRelease之前将删除IRP传递给下一个较低的驱动程序-我们可以在这里永远等待-下一个较低的驱动程序无法完成某些IRP,直到没有收到删除请求,并且我们不会释放删除锁定或RundownProtection

那么,为了什么我们需要解除锁或破败保护?因为我们可以让IRP_MN_REMOVE_设备与另一个IO请求并发。这个IO请求可以使用设备上的一些资源。当我们处理IRP\u MN\u REMOVE\u设备时,我们破坏了这个资源 s如果在IRP\u MN\u REMOVE\u设备中销毁IO请求后,我们将在IO请求中使用某些资源,会怎么样?认为不需要回答。为了防止这种情况发生,存在拆卸锁或减速保护。在使用将在删除中销毁的任何资源之前,需要调用IoAcquireRemoveLock或ExAcquireUndownProtection,并仅在返回ok状态时使用它。完成后,使用资源调用IoReleaseRemoveLock或exreleasererundownprotection。在IRP\u MN\u REMOVE\u设备中,我们称为IOreleaseRemovelock和Wait或ExWaitForRundownProtectionRelease。返回此调用后-我们可以确保没有人使用我们的资源,也不会使用更多对IOAcquireMemovelock或ExAcquireUndownProtection的调用返回错误状态false。此时,我们可以安全地开始销毁资源:释放内存等,调用IoDetachDevice、IoDeleteDevice

指向下一个较低设备的指针-这也是资源,我们在处理IO请求时使用它,在IRP_MN_REMOVE_设备中通过调用IoDetachDevice销毁它。真正正确的调用IofCallDriver\u nextDeviceObject,Irp;在调用IoDetachDevice_nextDeviceObject后处理一些IO请求;内部IRP\u MN\u移除\u设备?因为这种删除锁定或我使用自己的rundown保护在函数和过滤器驱动程序中经常使用。对于总线驱动程序,我们通常没有指向下一个较低设备的指针,PDO没有连接到另一个设备,当FDO连接到PDO并且过滤器总是连接到某个设备时,可能根本不需要锁或停机保护。这取决于-是否存在另一种资源-在删除时使用和销毁


对于总线设备-通常情况下,当我们得到IRP_MN_REMOVE_设备2次-首先在设备标记为RemovePending之前-所以我们转到第4点。在设备被标记为RemovePending之后,总线驱动程序最近对总线关系的IRP\u MN\u查询\u设备\u关系请求的响应中没有包含该设备。我们最终销毁了资源,并致电IoDeleteDevice

@RBMM谢谢您的回答,非常清楚。因此,我们的想法是在处理另一个请求时保护资源设备对象、其扩展等不被释放。我仍然不明白的是:我们将remove lock存储在设备扩展中,所以要获取它,我们需要访问这个扩展。在我们访问IoDeleteDevice时,对IoDeleteDevice的调用尚未执行,因此设备对象及其扩展名已被释放,这一保证在哪里?@new_user-如果有人向我们发送IO请求-他必须有指向DeviceObject的指针,并且必须确保他有对它DeviceObject的引用。因此,DeviceObject和DeviceExtension作为内存存储是有效的。但是设备对象的状态——已经是另一个问题了——他引用了对象——而不是保证它的状态。只有记忆有效性。和rundown protection,用于保护在对象本身被销毁之前可以被销毁的对象部分。@new_user-例如,我在启动设备上分配内存缓冲区devext->Buf。io请求使用此Buf。有人在我的设备上打开了指向我的设备甚至文件的指针,并向它发送ioctl。在发送方不释放自己的referenceclose文件之前,设备对象本身将是有效的内存存储。即使我们调用IoDeleteDevice,在最后一次引用转到0后,内存也将被释放。但是,如果我们在concurent WO中通过此ioctl收到删除请求,并且不会使用耗尽保护-我们可以释放Buf,直到ioctl使用它。调用ExWaitForRundownProtectionRelease下一步-如果此时有人使用Buf,我们将等待。并立即禁用更多使用Buf。在这之后,我们就可以安全自由了Buf@RbMmGreat非常感谢。对不起,如果我太好奇了,我还有一个问题。我有DispatchDeviceControl、DispatchCleanup和DispatchClose处理程序。这些请求从用户模式发送到总线FDO,换句话说,我们在总线FDO上打开了文件,因此总线FDO及其扩展名作为内存存储的有效性得到了保证,但我们需要访问子PDO来完成请求,我们使用设备名称空间的概念:ChildPDO=device_OBJECT*IoGetCurrentIrpStackLocationIrp->FileObject->FsContext;