IRP completion function: iofcompleterequest
1. Completion of IRP
1. What do I do after IRP is complete (Simple Description )?
A. Execute <finished routine>
B. Release the buffer (it is possible to copy it back to the "user layer", see the details below)
C. Delete IRP
2. How to complete an IRP?
A. Call iocompleterequest, while iocompleterequest is a "macro" =
Iofcompleterequest, "F" of "IOF" indicates "quick call", that is, "register transfer parameters ".
3. Synchronization and asynchronous IRP completion:
A. synchronous IRP: the primary function <to wait until all operations are completed <to return>. When the return result is returned, iofcompleterequest must be called to complete IRP.
B. asynchronous IRP: The main function <NO> can be returned after the required operation is completed. However, the IRP must <suspend: iomarkirppending> and return status_pending.
C. When IRP is completed, you must do some <Aftercare Work>
D. One IRP can only be completed in one place, that is, only one iofcompleterequest call can be performed.
Ii. aftercare after IRP is completed
A. from bottom to bottom, check whether the completionroutine is set for every io_stack scan. If so, execute the completionroutine in sequence, which is set by "iosetcompletionroutine ".
B. If the IRP is associated with the IRP, you must call iofcompleterequest to complete the "primary IRP" of the "it". (This is why I am not familiar with the "correlated IRP" yet ?)
C. Call iopcompleterequest (note that it is not iofcompleterequest)
Iii. iofcompleterequest Function
A. determine the type of our IRP "memory operations"
(A) if it is a "buffer", you must take the "memory buffer requested by the kernel" into the "user memory buffer", such:
Rtlcopymemory (IRP-> userbuffer,
IRP-> associatedirp. systembuffer,
IRP-> iostatus. information );
IRP-> userbuffer points to "user buffer", which is saved when you apply for IRP.
IRP-> associatedirp. systembuffer is directed to the "kernel buffer". It is also applied when "applying for IRP ".
(B) if it is a "direct mode", then:
For (MDL = IRP-> mdladdress; MDL = nextmdl)
{
Nextmdl = MDL-> next;
Iofreemdl (MDL );
}
(See note)
B. Set the "event synchronization object" uploaded by the user"
C. Remove the "IRP" from the "IRP queue" of the "Thread"
D. "release" IRP
Note: Various <memory operations>:
A. "buffer" Mode
If (deviceobject-> flags & do_buffered_io) // If the <buffer> mode is used
{
IRP-> associatedirp. systembuffer = exallocatepoolwithtag (nonpagedpool,
Length,
Tag_sysb );
IRP-> userbuffer = buffer; // Save the Data Pointer of <user layer>
}
B. "direct access" mode (isn't "ing mode" better ?)
If (deviceobject-> flags & do_direct_io)
{
MDL = ioallocatemdl (buffer, length, false, true, IRP );
MMP robeandlockpages (MDL, previusmode, iowriteaccess );
}
C. "None of the two modes"
IRP-> userbuffer = buffer; // directly access the data at the <user layer>. Note that the <thread switching> cannot be enabled, otherwise, a memory access error may occur (the address used to access other process spaces is gone)