分层驱动模型中IRP的传递与完成

[转载]分层驱动模型中IRP的传递与完成

本文转自 Hanke空间,原文地址: http://hi.baidu.com/hankebao/blog/item/7e8329804e0ce9d2bc3e1e2b.html
---------
在Windows分层驱动模型中,设备栈中的设备一般都是通过对上层传来的IRP做相应的处理来实现驱动的功能。这里对常用的几种IRP传递及完成的方式进行归纳和总结:

1. 在本层驱动中完成

1.1 在本层驱动中以 同步方式完成
在本层同步完成一般做完相应处理后,设置Irp->IoStatus.Status和Irp->IoStatus.Information,调用IoCompleteRequest完成该IRP,return IRP的完成状态即可。

1.2 在本层驱动中以异步方式完成
在本层异步完成一般是得到IRP后将其 入队/起线程另行处理,同时调用IoMarkIrpPending 将该IRP标记为Pending,之后即可return STATUS_PENDING。此时该 IRP并未真正完成,需待未决的操作在他处完成后调用IoCompleteRequest才真正完成


2. 转发至下层驱动

2.1 本层不作处理
有时对于某些IRP,本层驱动不需要做任何处理。此时可调用 IoSkipCurrentIrpStackLocation跳过当前设备栈,然后调用 IoCallDriver将IRP转发至下层驱动,并将转发的结果直接返回。此种处理方式并 不需要关心下层驱动处理IRP的方式究竟是同步还是异步。IRP转发至下层后就与己无关了

2.2 同步转发方式
有时IRP在本层无法直接处理,需要将其转发至下层, 待下层处理完后在其结果上进行修改再将其返回(和上面矛盾?)。这时可以采用同步转发方式进行处理。首先在相应 dispatch routine中初始化一个未激发的event,调用 IoCopyCurrentIrpStackLocationToNext将本层设备栈参数复制到下层。然后设置一个 CompletionRoutine,将刚才 初始化过的event作为context传给它。之后调用 IoCallDriver转发IRP至下层,并判断 返回值是否为STATUS_PENDING是则wait之前的event在CompletionRoutine中判断该IRP是否PendingReturned,是则说明之前IoCallDriver返回了STATUS_PENDING,于是 激发eventCompletionRoutine返回STATUS_MORE_PROCESSING_REQUIRED使我们的 dispatch routine重新取得对该IRP的控制权。本层dispatch等待结束再次获得控制权后,进行相应处理,之后需 再次调用IoCompleteRequest完成该IRP
同步转发是驱动中常用的一种IRP处理方式。一般会将本层dispatch转发IRP至下层并等待CompletionRoutine激发event的行为独立成一个ForwardIrpSynchronous的函数。几个dispatch只需一个ForwardIrpSynchronous,代码相对简单。
注意不要在本层dispatch中调用IoMarkIrpPending,因为上层的请求在本层被同步处理了。在同步转发中,如果下层驱动也采用同步方式处理,则本层dispatch不会(也不需要)wait,IoCallDriver返回时CompletionRoutine已经被调用,性能上也没有什么损失。

2.3 异步转发方式
异步转发也能在下层驱动完成IRP时获得处理的机会,其主要是采用了异步处理机制。首先本层dispatch调用IoCopyCurrentIrpStackLocationToNext将本层设备栈参数复制到下层,设置相应的CompletionRoutine,然后调用IoCallDriver将IRP转发至下层驱动,并 将转发的结果直接return给上层调用者。在 CompletionRoutine中再判断该IRP是否PendingReturned,是则需要调用IoMarkIrpPending。之后可对下层驱动处理该IRP的结果进行相应操作。 最后返回STATUS_CONTINUE_COMPLETION(同STATUS_SUCCESS)。
异步转发在异步处理时性能最佳,但处理的逻辑放在了CompletionRoutine中,因此多个dispatch需要编写多个CompletionRoutine。而同步转发往往几个dispatch只需一个ForwardIrpSynchronous即可,代码相对简单。


值得注意的是,各个dispatch routine运行的IRQL是由调用关系决定的。如果上层调用者有运行在DISPATCH_LEVEL的可能,则本层的dispatch也需要按照运行在DISPATCH_LEVEL来设计。比如传递至本层dispatch的IRP是在上层驱动的StartIO例程中转发的,则本层处理该类IRP的代码就可能运行在DISPATCH_LEVEL。

你可能感兴趣的:(分层驱动模型中IRP的传递与完成)