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