Note
For optimal reliability and performance, use file system minifilter drivers with Filter Manager support instead of legacy file system filter drivers. To port your legacy driver to a minifilter driver, see Guidelines for Porting Legacy Filter Drivers.
Completion processing is performed in two stages. The first stage is performed in an arbitrary thread context, at IRQL <= DISPATCH_LEVEL. In this stage, the following tasks are performed:
Each completion routine registered for the IRP is called in turn, beginning with the lowest IRP stack location. If a completion routine returns STATUS_MORE_PROCESSING_REQUIRED, completion processing is halted.
If the IRP contains a memory descriptor list (MDL), any physical pages mapped by the MDL are unlocked.
The second phase of I/O completion is queued to the target (requesting) thread as a special kernel APC.
The second stage is performed in the context of the thread that originated the I/O request. It's executed as a special kernel APC and therefore runs at IRQL APC_LEVEL. In this stage, the following tasks are performed:
If the IRP represents a buffered operation, the contents of Irp->AssociatedIrp.SystemBuffer are copied to Irp->UserBuffer.
If the IRP contains an MDL, the MDL is freed.
The contents of Irp->IoStatus are copied to Irp->UserIosb so that the originator of the I/O request can see the final status of the operation.
If an event has been supplied in Irp->UserEvent, it's signaled. Otherwise, if there's a file object for this IRP, its event is signaled.
If the IRP was created by calling IoBuildDeviceIoControlRequest or IoBuildSynchronousFsdRequest, it's dequeued from the thread's pending I/O request list.
A user APC is queued, if the caller requested one.
The IRP is freed.
If completion processing for an IRP is halted because a completion routine returned STATUS_MORE_PROCESSING_REQUIRED, it can be resumed by calling IoCompleteRequest on the same IRP. When this situation happens, first-stage processing resumes, beginning with the completion routine for the driver immediately above the one whose completion routine returned STATUS_MORE_PROCESSING_REQUIRED.