Writing Postoperation Callback Routines
A file system minifilter driver uses one or more postoperation callback routines to filter I/O operations.
A postoperation callback routine can take one of the following actions:
- Accomplish completion work directly in postoperation routine. All the completion work can be accomplished at IRQL <= DISPATCH_LEVEL.
- Accomplish completion work at a safe IRQL. Return FLT_STATUS_MORE_PROCESSING_REQUIRED and queue a worker thread to allow processing at safe IRQL. When processing is complete, the worker thread calls FltCompletePendedPostOperation to continue postoperation processing.
- Cancel a successful CREATE operation.
Postoperation callback routines are similar to the completion routines that are used in legacy file system filter drivers.
A minifilter driver registers a postoperation callback routine for a particular type of I/O operation in the same way it registers a preoperation callback routine—that is, by storing the callback routine's entry point in the OperationRegistration member of the FLT_REGISTRATION structure that the minifilter driver passes as a parameter to FltRegisterFilter in its DriverEntry routine.
Minifilter drivers receive only those types of I/O operations for which they have registered a preoperation or postoperation callback routine. A minifilter driver can register a preoperation callback routine for a given type of I/O operation without registering a postoperation callback, and vice versa.
Every postoperation callback routine is defined as follows:
typedef FLT_POSTOP_CALLBACK_STATUS
(*PFLT_POST_OPERATION_CALLBACK) (
IN OUT PFLT_CALLBACK_DATA Data,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN PVOID CompletionContext,
IN FLT_POST_OPERATION_FLAGS Flags
);
Like a completion routine, a postoperation callback routine is called at IRQL <= DISPATCH_LEVEL, in an arbitrary thread context.
Because it can be called at IRQL = DISPATCH_LEVEL, a postoperation callback routine cannot call kernel-mode routines that must be called at a lower IRQL, such as FltLockUserBuffer or RtlCompareUnicodeString. For the same reason, any data structures that are used in a postoperation callback routine must be allocated from nonpaged pool.
The following situations are several exceptions to the preceding rule:
If a minifilter driver's preoperation callback routine returns FLT_PREOP_SYNCHRONIZE for an IRP-based I/O operation, the corresponding postoperation callback routine is called at IRQL <= APC_LEVEL, in the same thread context as the preoperation callback routine.
The postoperation callback routine for a fast I/O operation is called at IRQL = PASSIVE_LEVEL, in the same thread context as the preoperation callback routine.
Post-create callback routines are called at IRQL = PASSIVE_LEVEL, in the context of the thread that originated the IRP_MJ_CREATE operation.
When the filter manager calls a minifilter driver's postoperation callback routine for a given I/O operation, the minifilter driver temporarily controls the I/O operation. The minifilter driver retains this control until it does one of the following:
Returns FLT_POSTOP_FINISHED_PROCESSING from the postoperation callback routine.
Calls FltCompletePendedPostOperation from a work routine that has processed an IRP-based I/O operation that was pended in the postoperation callback routine.
This section includes:
Performing Completion Processing for an I/O Operation
Pending an I/O Operation in a Postoperation Callback Routine
Failing an I/O Operation in a Postoperation Callback Routine