IRP完成函數:IofCompleteRequest
一.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;//直接存取<使用者層>的資料,注意不能讓<線程切換>,不然可能會發生訪問記憶體錯誤(訪問別的進程空間的地址去了)