IO_REMOVE_LOCK使用方法小结(转载加改正)
原文链接: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使用方法小结(转载加改正)的更多相关文章
- ASP.NET对路径"C:/......."的访问被拒绝 解决方法小结 [转载]
问题: 异常详细信息: System.UnauthorizedAccessException: 对路径“C:/Supermarket/output.pdf”的访问被拒绝. 解决方法: 一.在IIS中的 ...
- python中执行shell命令的几个方法小结(转载)
转载:http://www.jb51.net/article/55327.htm python中执行shell命令的几个方法小结 投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014- ...
- 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理
服务器文档下载zip格式 刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...
- 【转】TextView长按复制实现方法小结
有这么一个需求,用户在浏览文本信息时希望长按信息就能弹出复制的选项方便保存或者在别的页面使用这些信息.类似的, 就像长按WebView或者EditText的内容就自动弹出复制选项. 这里面主要是2个特 ...
- static使用方法小结
static使用方法小结 statickeyword是C, C++中都存在的keyword, 它主要有三种使用方式, 当中前两种仅仅指在C语言中使用, 第三种在C++中使用(C,C++中详细细微操作不 ...
- T-SQL切割字符串方法小结
T-SQL切割字符串方法小结,只有表值函数那个是自己的思想,其它都是来源于网络的思想,请大家不要笑话,嘻嘻~网上大牛太多,这点东西虽然上不了台面,但是也算是自己的一个学习吧,能够对一个人有用也行.再不 ...
- PowerDesigner实用方法小结(1)
PowerDesigner使用方法小结 PowerDesigner多用来进行数据库模型设计,具有SQL语句自动生成等功能.当然,也有不少缺点,比如团队分享. 一.设置PowerDesigner模型视图 ...
- (转)java判断string变量是否是数字的六种方法小结
java判断string变量是否是数字的六种方法小结 (2012-10-17 17:00:17) 转载▼ 标签: it 分类: 转发 1.用JAVA自带的函数 public static boolea ...
- 梯度提升树(GBDT)原理小结(转载)
在集成学习值Adaboost算法原理和代码小结(转载)中,我们对Boosting家族的Adaboost算法做了总结,本文就对Boosting家族中另一个重要的算法梯度提升树(Gradient Boos ...
随机推荐
- springside springmvc 的一个SB问题
<form id="inputForm" modelAttribute="order" action="${ctx}/myorder/orde ...
- localStorage 便签功能实现
之前利用localStorage写过手机便签应用,因为蛋疼的换了台三星的屌丝级手机,木 有了测试的工具,没能继续优化维护下去.而在网页上实现便签功能目前来说似乎没有太大 的意义,因为不论是 Firef ...
- 【转载】test和cmp比较
标 题:test和cmp一个很菜很基础的话题! 作 者: FTBirthday 时 间:2003/05/19 01:14am 链 接:http://bbs.pediy.com 看过破解教程,都知道te ...
- uva 10608
简单并查集 水水..... #include <cstdio> #include <cstring> #define maxn 30005 int fa[maxn],ans[ ...
- javascript closure
http://www.jibbering.com/faq/notes/closures/ http://hi.baidu.com/bluedream_119/item/938dcd082b1e1880 ...
- 【mysql的设计与优化专题(5)】慢查询详解
查询mysql的操作信息 show status -- 显示全部mysql操作信息 show status like "com_insert%"; -- 获得mysql的插入次数; ...
- SGU 130
SGU130,用k条弦将一个圆分成k+1份的方法数. #include <iostream> #include <vector> #include <string> ...
- 简单的神经元算法实现(python)
参考python代码如下 #perceptron x=[[1 ,0, 0],[1,0,1],[1, 1, 0],[1, 1, 1],[0,0,1],[0,1,0],[0,1,1],[0,0,0]] y ...
- Annotation【转】
1.Annotation的工作原理: JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型.该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的c ...
- 安装安装.net framework过程中出现的问题
1.安装Microsoft..net framework2.0 SP2 出现 必须使用控制面板中的打开或关闭windows功能,安装或配置.net framework2.0 SP2 原因:可以打开控制 ...