一.IRP的完成
1.IRP完成后,做些什么(简单描述)?
A.执行<完成Routine>
B.释放(有可能要复制还给“用户层”,见下面详细)缓冲区
C.删除IRP
2.怎么完成一个IRP?
A.调用IoCompleteRequest,而IoCompleteRequest是一个“宏”== IofCompleteRequest,“Iof”的“f”表示是“快速调用”,即采用“寄存器传递参数”。
3.同步与异步IRP的完成:
A.同步IRP:主功能函数<要>等到完成所有操作<才返回>,返回的时候,必须调用IofCompleteRequest完成IRP
B.异步IRP:主功能函数<不用>等到所要求的操作完成,就能返回,但是此时的IRP必须必须<挂起:IoMarkIrpPending>,并且返回STATUS_PENDING
C.IRP完成的时候,必须做一些<善后的工作>
D.一个IRP,只能在一个地方被完成,即只能调用一次IofCompleteRequest
二.IRP完成后的<善后工作>
A.从下向到,扫描每一次IO_STACK,是否设置了CompletionRoutine,如果有,依次执行,该CompletionRoutine是由“IoSetCompletionRoutine”设置的
B.如果该IRP是关联IRP的话,必须调用IofCompleteRequest,完成“它”的“主IRP”(这是暂时还不大了解“关联IRP”到底什么用处?)
C.调用IopCompleteRequest(注意不是IofCompleteRequest)
三.IofCompleteRequest函数
A.判断我们的IRP的“内存操作”是什么类型
(a)如果是“缓冲区”的话,那么必须把在“内核申请的内存缓冲区”负责到“用户内存缓冲区”里面去,像:
RtlCopyMemory(Irp->UserBuffer,
Irp->AssociatedIrp.SystemBuffer,
Irp->IoStatus.Information);
Irp->UserBuffer是指向“用户缓冲区”,它“申请IRP”的时候,保存的
Irp->AssociatedIrp.SystemBuffer是指向“内核缓冲区”,它也是在“申请IRP”的时候,申请的
(b)如果是“直接模式”的话,就:
for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
{
NextMdl = Mdl->Next;
IoFreeMdl(Mdl);
}
(见:注)
B.设置用户传过来的“事件同步对象”
C.从“线程”的“IRP队列”中移除该“IRP”
D.“释放”IRP
注:IRP各种<内存操作的方式>:
A.“缓冲区”模式
if (DeviceObject->Flags & DO_BUFFERED_IO)//如果采用了<缓冲区>模式
{
Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
Length,
TAG_SYSB);
Irp->UserBuffer = Buffer;//保存<用户层>的数据指针
}
B.“直接访问”模式(叫“映射模式”不会更好听一点吗?)
if (DeviceObject->Flags & DO_DIRECT_IO)
{
Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);
MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);
}
C.“2种模式都不是”模式
Irp->UserBuffer = Buffer;//直接访问<用户层>的数据,注意不能让<线程切换>,不然可能会发生访问内存错误(访问别的进程空间的地址去了)