首页
社区
课程
招聘
[求助]IoCopyCurrentIrpStackLocationToNext等的疑问
发表于: 2011-4-11 14:21 8749

[求助]IoCopyCurrentIrpStackLocationToNext等的疑问

2011-4-11 14:21
8749
1、
IoCopyCurrentIrpStackLocationToNext是拷贝本层的IO_STACK_LOCATION 到下一层。在楚狂人的驱动教程中说:
如果对irp完成之后的事情有兴趣,并打算在完成函数中处理,应该首先拷贝当前 IO_STACK_LOCATION(IoCopyCurrentIrpStackLocationToNext),然后指定完成函数,并返回 IoCallDriver()所返回的status.完成函数中,不需要调用IoCompleteRequest!直接返回Irp的当前状态即可.但是IoCopyCurrentIrpStackLocationToNext是这样的:
#define IoCopyCurrentIrpStackLocationToNext( Irp ) { \   
    PIO_STACK_LOCATION __irpSp;        \   
    PIO_STACK_LOCATION __nextIrpSp;    \   
    __irpSp = IoGetCurrentIrpStackLocation( (Irp) );     \   
    __nextIrpSp = IoGetNextIrpStackLocation( (Irp) );    \   
    RtlCopyMemory(__nextIrpSp, __irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); \    
    __nextIrpSp->Control = 0; }  
也就是说他并没有拷贝当前的完成例程给下层,而是通过IoSetCompletionRoutine来设置的 这样一来的话,拷不拷贝本层的IO_STACK_LOCATION 到下层不都是没有关系的了?因为下层的IO_STACK_LOCATION 有他自己的结构内容,何必要用本层的拷贝过去呢?
2、
#define IoSetCompletionRoutine(irp,routine,completioncontext,success,error,cancel)\
#{ PIO_STACK_LOCATION irpsp;\
#ASSERT((success)|(error)|(cancel)?(routine)!=NULL:TRUE);\
#irpsp=IoGetNextIrpStackLocation((irp));\
#irpsp->completionroutine=(routine);\
#irpsp->context=(completioncontext);\
#irpsp->control=0;\
#if((success)){irpsp->control=SL_INVOKE_ON_SUCCESS;}\
#if((error)){irpsp->control  |= SL_INVOKE_ON_ERROR;}\
#if((cancel)){irpsp->control  |=  SL_INVOKE_ON_CANCEL;}  }\
这样一来IoSetCompletionRoutine不是设置的下层的完成例程么?为什么是设置下层的完成例程?为什么不是本层的?

3、
PIO_STACK_LOCATION IrpSp;   
PIO_STACK_LOCATION NextIrpSp;   
  
IrpSp = IoGetCurrentIrpStackLocation(Irp);   
NextIrpSp = IoGetNextIrpStackLocation(Irp);   
  
*NextIrpSp = *IrpSp;   
  
return IoCallDriver(NextDeviceObject, Irp);
这种方法OSR中说IO_STACK_LOCATION中有两个成员CompletionRoutine、Context,即完成例程和完成例程的上下文参数。也就是说方法二会让Lb层拥有这两个原本不一定会属于它的成员。如果这两个成员都是NULL,那还好。一旦这两个成员有有效的内容,那么就会导致"an eventual blue screen"。但是在filemon源码的FilemonHookRoutine例程靠后中有
*nextIrpStack = *currentIrpStack;
但是随后
#if defined(_IA64_)
        IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) (ULONG_PTR) seqNum, TRUE, TRUE, TRUE );
#else
        IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) seqNum, TRUE, TRUE, TRUE );
#endif
而并没有出现什么蓝屏。而且我不明白为什么会出现蓝屏原本不属于他的成员CompletionRoutine、Context在IoSetCompletionRoutine不就是设置NextIrpSp 自己的成员么?(IoSetCompletionRoutine的定义  )

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 195
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
1、这个MSDN上写的很清楚,惭愧读了两边都没注意,整理笔记的时候才发现的:

Each driver in such a chain is responsible for calling IoGetNextIrpStackLocation, then setting up the next-lower driver's I/O stack location. Any higher-level driver's I/O stack location can also be used to store context about an operation so that the driver's IoCompletion routine can perform its cleanup operations.
(后面这句话还是不理解为什么IoSetCompletionRoutine是设置的下层的completionroutine 而却说上层store context about an operation
代码明明是这样写的
IoSetCompletionRoutine中
#irpsp=IoGetNextIrpStackLocation((irp));\
#irpsp->completionroutine=(routine);\
#irpsp->context=(completioncontext);\



and

A higher-level driver in a chain of layered drivers can safely access only its own and the next-lower-level driver's I/O stack locations in any IRP. Such a driver must set up the I/O stack location for the next-lower-level driver in IRPs
2011-4-11 15:13
0
雪    币: 392
活跃值: (89)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
3
问题提的非常好,说明你思考问题很深入:

1,完成例程本来就是设置在当前堆栈的下一层堆栈里,这相当于是一个规范,也可以用实际的IRP的返回来理解。在完成例程里,根据返回不同的状态值,IRP的控制流可能会发生相应的变化,比如:...STATUS_MORE_PROCESSING,这样,下层堆栈执行完成例程后,会将IRP的控制权交付给本层堆栈。从这个意义上讲,完成例程,只能放在下层堆栈,实际上,设计也是这样的。

2,拷贝当前堆栈的内容到下层堆栈,只是为了保证执行环境一样。

在一个设备栈中,高层设备只能访问自己的设备栈或者下层设备栈,这就要求这个驱动必须要为下层设置IO堆栈,但不是必须的。每个堆栈中,context字段的值是唯一的,会标识一些pending等状态位,表示不同的完成状态,所以这个字段不可以随意复制。
2011-4-12 09:33
0
雪    币: 195
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢microdebug,你也是我更明确了为何本层做了改变就要使用IoCopyCurrentIrpStackLocationToNext了因为他不复制Context,在随后的IoSetCompletionRoutine设置。这也正印证了楚狂人说的:
如果对irp完成之后的事情有兴趣,并打算在完成函数中处理,应该首先拷贝当前 IO_STACK_LOCATION(IoCopyCurrentIrpStackLocationToNext),然后指定完成函数,并返回 IoCallDriver()所返回的status.
2011-4-12 11:33
0
雪    币: 216
活跃值: (144)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
5
mark~,暂时还没有LZ学的那么深入~~
2011-4-17 14:42
0
雪    币: 38
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
mark
2017-7-15 09:37
0
游客
登录 | 注册 方可回帖
返回
//