原文链接: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. NOSQL Mongo入门学习笔记 - 数据的基本插入(二)

    成功运行起来mongo之后,进入了命令行模式,mongo默认会选择test数据库 1. 使用db命令打印出来当前选定的数据库: > db test 2. 使用show dbs 命令可以打印出数据 ...

  2. CentOS6.4 安装 mongo-connector

    mongo-connector在python2.6.6版本下安装不成功,官方测试2.7,3.3正常 需要升级python2.7 具体步骤: 安装开发工具包: yum groupinstall &quo ...

  3. 1020: [SHOI2008]安全的航线flight - BZOJ

    Description在设计航线的时候,安全是一个很重要的问题.首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率.当飞机 ...

  4. ExtJS4.2学习(五)表格渲染与复选框

    鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-11-10/174.html --------------- ...

  5. [转载]自定义ASP.NET MVC Html辅助方法 TagBuilder

    在ASP.NET MVC中,Html辅助方法给我们程序员带来很多方便,其重要性也就不言自明.有时候,我们不想重复地写一些HTML代码,或者MS没有提供我们想要的那个HTML标签的Html辅助方法,那么 ...

  6. Window8 进不了PE如何设置BIOS

    如题,如今进入Win8时代,很多新出的机器都自带了WIN8.但是童鞋们想进PE进行操作的时候,发现进不了. 更改BIOS以下2处设置,即可使用第三方引导安装系统:Boot->Launch CSM ...

  7. Object-C中emoji与json的问题

    遇到一个问题,要储存iOS键盘输出的emoji表情到MySQL,我知道用blob+utf8是可以存的.但是现在我的这张表已经太大了,不可能去改类型.所以就想把emoji表情匹配出来,替换掉,再存.但是 ...

  8. web客户端通过ajaxfileupload方式上传文件

    fileUpload.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" ...

  9. 【.Net免费公开课】--授技.Net中的高帅富技术-"工作流"

    课程简介 免费公开课主题: .Net中的高帅富技术-“工作流” 公开课开课时间:     10月17日 19:30--21:30 公开课YY频道:       85155393   (重要:公开课QQ ...

  10. git rev-list

    git-rev-list - Lists commit objects in reverse chronological order 按照时间顺序倒序排列的commit Update: If all ...