原文链接:http://www.programlife.net/io_remove_lock.html

IO_REMOVE_LOCK(删除锁)的具体结构没有公开,WDK的文档中中查不到IO_REMOVE_LOCK。最开始看到IO_REMOVE_LOCK是在WDK的例子event中。下面是参考网上的一些资料之后的一点总结,错误的地方请指正。新增内容:WDK8.1 中是可以看到这个结构的,在wdm.h中。

为什么要用IO_REMOVE_LOCK? WDM 驱动程序在处理设备删除 IRP 并释放驱动程序分配的内存后可能接收到附加的 IRP。在处理附加的 IRP 时试图引用已经释放的内存会导致系统崩溃。驱动程序能够接收已删除设备的 IRP,这有两个原因:

1。在设备被删除后,另一个组件可以发送 I/O。要发送一个 IRP,组件获取目标设备或文件的指针并去除该设备对象上的引用(或者 I/O 管理器代表组件去除引用)。引用可以确保目标设备或文件对象的持续性,从而目标驱动程序可以访问设备对象和设备扩展。但是,除非组件已经在目标设备上注册了即插即用通知,否则它不能确定设备是否仍然存在。

2。在设备删除请求之前发送的 I/O 请求可能在目标驱动程序处理设备删除请求之后到达。这种情况是否发生取决于哪个组件在发送 I/O、目标驱动程序在设备堆栈中的位置以及为设备挂起的其他 I/O 请求。 通俗一点的解释:有时候I/O管理器发出的PnP请求会与其它I/O请求(如包含读写的请求)同时出现。这完全有可能,例如当你处理其它IRP时收到了IRP_MN_REMOVE_DEVICE请求。你必须自己避免这种麻烦产生,标准的做法是使用一个IO_REMOVE_LOCK对象和几个相关的内核模式支持例程。

防止设备被过早地删除的基本想法是在每一次开始处理请求时都获取删除锁,处理完成后释放删除锁。在你删除你的设备对象前,应确保删除锁未被使用。否则,你将等到这个锁的所有引用都被释放。下图显示了这个过程: IO_REMOVE_LOCK怎么用,IO_REMOVE_LOCK是什么

怎么使用IO_REMOVE_LOCK? 在驱动程序的设备扩展(DEVICE_EXTENSION)中定义IO_REMOVE_LOCK类型的变量,并在 AddDevice例程中调用IoInitializeRemoveLock对其进行初始化。

此后,无论何时,当你收到一个I/O请求时(除了IRP_MJ_CREATE),你就调用IoAcquireRemoveLock。如果删除设备的操作正在进行,则IoAcquireRemoveLock返回STATUS_DELETE_PENDING。否则,该函数将获得删除锁并返回STATUS_SUCCESS。一旦你完成一个I/O操作,就调用IoReleaseRemoveLock,该函数将释放删除锁以及目前未处理的删除操作。

当处理一个设备删除请求 (IRP_MN_REMOVE_DEVICE) 时,驱动程序通过调用 IoReleaseRemoveLockAndWait 来释放在其 DispatchPnP 例程中获取的删除锁。这个调用直到与删除锁关联的引用计数达到零时才返回,这表示删除锁的所有其他持有者都已经被释放。在 IoReleaseRemoveLockAndWait 返回之后,驱动程序将 IRP 沿其设备堆栈向下传递(如有必要),调用 IoDetachDevice 来从设备堆栈中删除其设备对象,然后释放在其 AddDevice 例程中分配的资源(例如池内存)。最后,驱动程序调用 IoDeleteDevice 来标记要删除的设备对象。

何时调用IoReleaseRemoveLock? 驱动程序何时应该调用 IoReleaseRemoveLock 取决于它如何处理IRP:通过将其传递给下一层驱动程序(不设置完成例程)、通过完成 IRP 而不将其传递给下一层驱动程序或者通过向下传递 IRP 并设置一个完成例程。

如果驱动程序将 IRP 传递给下一层驱动程序并且不设置 IoCompletion 例程,那么驱动程序应该在调用 IoCallDriver 之后调用 IoReleaseRemoveLock 来向下传递 IRP。

 NTSTATUS MyDispatchRoutine (
IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION devExt;
NTSTATUS status;
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
status = IoAcquireRemoveLock (&devExt->RemoveLock, Irp); if (!NT_SUCCESS (status)) {
// maybe device is being removed.
Irp->IoStatus.Information = ;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
} // Do request-specific processing . . . // Pass down the IRP and release the lock. IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (devExt->NextLowerDriver, Irp);
IoReleaseRemoveLock (&devExt->RemoveLock, Irp);
return status;
}

如果驱动程序完成 IRP 并且不将其传递给下一层驱动程序,那么驱动程序应该在调用 IoCompleteRequest 之后调用 IoReleaseRemoveLock,如下例所示:

 NTSTATUS MyDispatchRoutine (
IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PDEVICE_EXTENSION devExt;
NTSTATUS status;
devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
status = IoAcquireRemoveLock (&devExt->RemoveLock, Irp); if (!NT_SUCCESS (status)) {
// maybe device is being removed.
Irp->IoStatus.Information = ;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
} // Do request-specific processing . . .
// Request-specific processing is done. Complete the IRP
// and release the lock. Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT );
IoReleaseRemoveLock (&devExt->RemoveLock, Irp);
return status;
}

如果驱动程序将 IRP 传递给下一层驱动程序并设置一个 IoCompletion 例程,那么驱动程序将从 IoCompletion 例程调用 IoReleaseRemoveLock,如下所示:

 NTSTATUS MyCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) {
PDEVICE_EXTENSION data;
UNREFERENCED_PARAMETER (DeviceObject);
data = (PDEVICE_EXTENSION) Context;
IoReleaseRemoveLock (&data->RemoveLock, Irp);
return STATUS_SUCCESS;
}

IO_REMOVE_LOCK小结

只有在对设备对象的所有引用都被释放后,I/O 管理器才会真正删除该设备对象。因此,在驱动程序的设备删除处理完成之后,有效的设备对象和设备扩展可能仍然存在。但是,驱动程序已经释放其资源,从而使得存储在设备扩展中的这些资源的指针都变得无效。

如果驱动程序在其删除设备处理完成之后,但是 I/O 管理器删除设备对象之前接收到另一个 I/O 请求,那么就会发生问题。当驱动程序处理请求时,它可能试图从设备扩展取消对一个无效指针的引用,这会导致系统崩溃。

要防止这种问题,驱动程序应该为所有类型的 I/O 请求获取删除锁,而不仅仅是即插即用和电源请求。大部分驱动程序已经在其 DispatchPnP 和 DispatchPower 例程中获取了删除锁,从而防止在处理即插即用和电源 IRP 时删除设备。但是,因为其他类型的 IRP 可能在设备删除之后到达,所以驱动程序还应该在调度例程中为其他类型的 I/O 请求获得删除锁。

最简单的方法是在发送 IRP 时在 I/O 调度例程中调用 IoAcquireRemoveLock。IoAcquireRemoveLock 返回 STATUS_DELETE_PENDING 来指示正在删除设备。如果 IoAcquireRemoveLock 返回此状态(或者除 STATUS_SUCCESS 之外的任何状态),那么驱动程序应该拒绝 I/O 请求。

在取消引用存储在设备扩展中的任何指针之前,通过在发送 IRP 时在 I/O 调度例程中调用 IoAcquireRemoveLock 来获得删除锁。 如果 IoAcquireRemoveLock 不返回 STATUS_SUCCESS,那么拒绝 I/O 请求。 当驱动程序完成 IRP 处理时,调用 IoReleaseRemoveLock。 在设备删除处理期间调用 IoReleaseRemoveLockAndWait,然后调用 IoDetachDevice 和 IoDeleteDevice。 Reference(其实基本都是转来的,稍微整理了一下) 我的设备不见了。为什么我仍然收到 IRP? 《Programming the Microsoft Windows Driver Model》

--------------------------------------------------------------------------------

原作者:代码疯子(Wins0n)

Copyed From 程序人生 Home Page:http://www.programlife.net Source URL:http://www.programlife.net/io_remove_lock.html

IO_REMOVE_LOCK使用方法小结(转载加改正)的更多相关文章

  1. ASP.NET对路径"C:/......."的访问被拒绝 解决方法小结 [转载]

    问题: 异常详细信息: System.UnauthorizedAccessException: 对路径“C:/Supermarket/output.pdf”的访问被拒绝. 解决方法: 一.在IIS中的 ...

  2. python中执行shell命令的几个方法小结(转载)

    转载:http://www.jb51.net/article/55327.htm python中执行shell命令的几个方法小结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014- ...

  3. 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理

    服务器文档下载zip格式   刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...

  4. 【转】TextView长按复制实现方法小结

    有这么一个需求,用户在浏览文本信息时希望长按信息就能弹出复制的选项方便保存或者在别的页面使用这些信息.类似的, 就像长按WebView或者EditText的内容就自动弹出复制选项. 这里面主要是2个特 ...

  5. static使用方法小结

    static使用方法小结 statickeyword是C, C++中都存在的keyword, 它主要有三种使用方式, 当中前两种仅仅指在C语言中使用, 第三种在C++中使用(C,C++中详细细微操作不 ...

  6. T-SQL切割字符串方法小结

    T-SQL切割字符串方法小结,只有表值函数那个是自己的思想,其它都是来源于网络的思想,请大家不要笑话,嘻嘻~网上大牛太多,这点东西虽然上不了台面,但是也算是自己的一个学习吧,能够对一个人有用也行.再不 ...

  7. PowerDesigner实用方法小结(1)

    PowerDesigner使用方法小结 PowerDesigner多用来进行数据库模型设计,具有SQL语句自动生成等功能.当然,也有不少缺点,比如团队分享. 一.设置PowerDesigner模型视图 ...

  8. (转)java判断string变量是否是数字的六种方法小结

    java判断string变量是否是数字的六种方法小结 (2012-10-17 17:00:17) 转载▼ 标签: it 分类: 转发 1.用JAVA自带的函数 public static boolea ...

  9. 梯度提升树(GBDT)原理小结(转载)

    在集成学习值Adaboost算法原理和代码小结(转载)中,我们对Boosting家族的Adaboost算法做了总结,本文就对Boosting家族中另一个重要的算法梯度提升树(Gradient Boos ...

随机推荐

  1. embed标签遮住div层

    依然是上次的那个返工友情项目,当时帮忙用jquery ui写了一个漂浮的投票箱,就是类似点击一个项目然后就收藏到了投票箱中的效果.. 虽然不是很复杂,但是由于页面上有大面积的由kindeditor上传 ...

  2. vbe6ext.olb不能被加载 宏内存溢出

    今天想玩一下PowerPoint的宏,却发现玩不起来!!! 另外,每次打开ppt时都会提示vbe6ext.olb不能加载. 网上说重新下载个vbe6ext.olb然后复制到相应的路径.我也试着下载,然 ...

  3. C# DataTable

    http://www.cnblogs.com/xun126/archive/2010/12/30/1921557.html http://msdn.microsoft.com/zh-cn/librar ...

  4. PAT-乙级-1040. 有几个PAT(25)

    1040. 有几个PAT(25) 时间限制 120 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CAO, Peng 字符串APPAPT中包含了两个单 ...

  5. PAT-乙级-1015. 德才论 (25)

    1015. 德才论 (25) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Li 宋代史学家司马光在<资治通鉴&g ...

  6. 深入理解计算机各种类型大小(sizeof)

    深入理解计算机各种类型大小(sizeof)   // Example of the sizeof keyword size_t  i = sizeof( int ); struct align_dep ...

  7. POJ2187Beauty Contest

    http://poj.org/problem?id=2187 题意 :有一个农场有N个房子,问最远的房子相距多少距离 . 思路 :凸包,旋转卡壳,通过寻找所有的对锺点,找出最远的点对. #includ ...

  8. hibernate annotation注解 columnDefinition用法

    column注解中的columnDefinition属性用于覆盖数据库DDL中的语句:(MySql) @Column(columnDefinition = "int(11) DEFAULT ...

  9. [itint5]完全二叉树节点个数的统计

    http://www.itint5.com/oj/#4 这题是利用完全二叉树的性质计算节点数目.那么是通过比较左右子树的最左结点的高度来看那边是满的,然后递归计算. //使用getLeftChildN ...

  10. Spring下载地址

    spring官方网站改版后,不提供直接下载,而是通过maven下载,所以将直接下载的地址给出: http://maven.springframework.org/release/org/springf ...