Writing Postoperation Callback Routines

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 asFltLockUserBuffer or RtlCompareUnicodeString. For the same reason, any data structures that are used in a postoperation callback routine must be allocated from nonpaged pool.

和完成例程一样,postoperation 回调函数在arbitrary线程上下文dispatch 级别上被调用,所以在此回调函数中不能调用那些必须在低IRQL级别上调用的函数,例如FltLockUserBuffer 或者 RtlCompareUnicodeString,同样的道理,此回调函数用到的结构体必须在非分页内存上分配。

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.

然而在某些情况下postoperation 回调函数并不处于dispatch级别,情况如下:

  • 如果preoperation 回调函数对IRP-based IO操作返回了FLT_PREOP_SYNCHRONIZE,那么postoperation 回调函数将处于与preoperation 回调函数同样的进程上下文,并且IRQL小于等于APC级别
  • fast IO操作postoperation 回调函数处于与preoperation 回调函数同样的进程上下文,并且IRQL为passive级别。
  • Post-create 回调函数IRQL为passive级别,并且处于发起IRP_MJ_CREATE 操作的线程上下文

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
当过滤管理器调用minifilter驱动的postoperation 回调函数时,minifilter驱动暂时拥有IO操作的控制权,直到它做了以下事
  • postoperation 回调函数时返回 FLT_POSTOP_FINISHED_PROCESSING
  • 从某个工作例程调用FltCompletePendedPostOperation 结束之前挂起的 IRP-based I/O操作
Performing Completion Processing for an I/O Operation

In addition, when a minifilter driver instance is being torn down, the filter manager "drains" any I/O operations for which the instance has received apreoperation callback and is awaiting a postoperation callback. In this situation, the filter manager calls the minifilter driver's postoperation callback routine, even if the I/O operation has not been completed, and sets the FLTFL_POST_OPERATION_DRAINING flag in the Flags input parameter.

当一个过滤驱动实例被拆卸时,过滤管理器“抽干”所有的那些preoperation 回调函数已被调用、正在等待postoperation 回调函数调用的IO操作。在这种情形下,过滤管理器调用这个过滤驱动的postoperation 回调函数,即使这些IO操作还未被完成,回调函数的参数Flags值为FLTFL_POST_OPERATION_DRAINING。

When the FLTFL_POST_OPERATION_DRAINING flag is set, the minifilter driver must not perform normal completion processing. Instead, it should perform only necessary cleanup, such as freeing memory that the minifilter driver allocated for theCompletionContext parameter in its preoperation callback routine, and return FLT_POSTOP_FINISHED_PROCESSING. 

若FLTFL_POST_OPERATION_DRAINING 标志位被设置,minifilter驱动不能执行普通的完成操作。它应该只执行一些清理操作,例如释放为参数CompletionContext 分配的内存。并最后返回FLT_POSTOP_FINISHED_PROCESSING。

As noted in Writing Postoperation Callback Routines, thepostoperation callback routine for an IRP-based I/O operation can be called at IRQL = DISPATCH_LEVEL, unless the minifilter driver's preoperation callback routine synchronized the operation by returning FLT_PREOP_SYNCHRONIZE or the operation is a create operation, which is inherently synchronous. (For more information about this return value, seeReturning FLT_PREOP_SYNCHRONIZE.)

However, for IRP-based I/O operations that are not already synchronized, minifilter drivers can use to two techniques to ensure that completion processing is performed at IRQL <= APC_LEVEL.

The first technique is for the postoperation callback routine to pend the I/O operation until completion processing can be performed at IRQL <= APC_LEVEL. This technique is described inPending an I/O Operation in a Postoperation Callback Routine.

The second technique is for the minifilter driver's postoperation callback routine to callFltDoCompletionProcessingWhenSafe. FltDoCompletionProcessingWhenSafe pends the I/O operation only if the current IRQL is >= DISPATCH_LEVEL. Otherwise, this routine executes the minifilter driver'sSafePostCallback routine immediately. This technique is described in FltDoCompletionProcessingWhenSafe.  

一般而言,对于IRP-based IO操作,其postoperation 回调函数处于dispatch级别,除非其对应的preoperation 回调函数返回FLT_PREOP_SYNCHRONIZE 或者是一个创建操作。

对于那些非同步的IRP-based IO操作,minifilter驱动可以使用两种技术确保完成操作发生在<=APC级别

  1. 第一种方案为在postoperation 回调函数挂起IO操作直到完成操作可以在IRQL <= APC_LEVEL级别执行
  2. 第二种方案为在postoperation 回调函数调用FltDoCompletionProcessingWhenSafeFltDoCompletionProcessingWhenSafe仅在IRQL大于等于dispatch级别是挂起IO操作,否则会立即执行minifilter驱动的SafePostCallback 回调函数。

Pending an I/O Operation in a Postoperation Callback Routine

A minifilter driver's postoperation callback routine can pend an I/O operation by performing the following steps:

  1. Calling FltAllocateDeferredIoWorkItem to allocate a work item for the I/O operation.
  2. Calling FltQueueDeferredIoWorkItem to post the I/O operation to a system work queue.
  3. Returning FLT_POSTOP_MORE_PROCESSING_REQUIRED.
minifilter驱动执行以下动作去挂起一个IO操作
  1. 调用FltAllocateDeferredIoWorkItem 为IO操作分配一个工作项
  2. 调用FltQueueDeferredIoWorkItem将IO操作发送至系统工作队列
  3. 返回FLT_POSTOP_MORE_PROCESSING_REQUIRED

Note that the call to FltQueueDeferredIoWorkItem will fail if any of the following conditions are true:

  • The operation is not an IRP-based I/O operation.
  • The operation is a paging I/O operation.
  • The TopLevelIrp field of the current thread is not NULL. (For more information about how to find the value of this field, seeIoGetTopLevelIrp.)
  • The target instance for the I/O operation is being torn down. (The filter manager indicates this situation by setting the FLTFL_POST_OPERATION_DRAINING flag in theFlags input parameter to the postoperation callback routine.)
在以下条件 FltQueueDeferredIoWorkItem 将会失败
  • 操作不是IRP-based I/O操作
  • 操作时分页IO
  • 当前线程的TopLevelIrp 域非空
  • 目标实例正在被卸载

Minifilter drivers must be prepared to handle this failure. If your minifilter driver cannot handle such failures, you should consider using the technique that is described inReturning FLT_PREOP_SYNCHRONIZE instead of pending the I/O operation.

minifilter驱动必须处理这些错误。如果你不能处理这些错误,你应该考虑使用 Returning FLT_PREOP_SYNCHRONIZE 介绍的技术。

After the minifilter driver's postoperation callback routine returns FLT_POSTOP_MORE_PROCESSING_REQUIRED, the filter manager will not perform any further completion processing for the I/O operation until the minifilter driver's work routine callsFltCompletePendedPostOperation to return control of the operation to the filter manager. The filter manager will not perform any further processing in this situation even if the work routine sets a failure NTSTATUS value in theIoStatus.Status field of the callback data structure for the operation.

The work routine that dequeues and performs completion processing for the I/O operation must callFltCompletePendedPostOperation to return control of the operation to the filter manager. 


Failing an I/O Operation in a Postoperation Callback Routine

A minifilter driver's postoperation callback routine can fail a successful I/O operation, but simply failing an I/O operation does not undo the effect of the operation. The minifilter driver is responsible for performing any processing that is needed to undo the operation.

minifilter驱动的postoperation回调函数可以使一个成功的IO操作失败,但是只是简单的是IO操作失败不会撤销已做的操作,minifilter驱动负责执行那些需要撤销的操作

For example, a minifilter driver's post-create callback routine can fail a successful IRP_MJ_CREATE operation by performing the following steps:

  1. Calling FltCancelFileOpen to close the file that was created or opened by the create operation. Note thatFltCancelFileOpen does not undo any modifications to the file. For example,FltCancelFileOpen does not delete a newly created file or restore a truncated file to its previous size.
  2. Setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation. This value must be a valid error NTSTATUS value, such as STATUS_ACCESS_DENIED.
  3. Setting the callback data structure's IoStatus.Information field to zero.
  4. Returning FLT_POSTOP_FINISHED_PROCESSING.

例如,minifilter驱动在post-create函数处理一个成功的 IRP_MJ_CREATE 操作时,可以执行以下动作使其失败:

  1. 调用FltCancelFileOpen关闭创建或者打开的文件,FltCancelFileOpen不会撤销文件的任何修改,例如FltCancelFileOpen不会删除新创建的文件或者还原一个截断的文件到原来的大小
  2. 设置回调数据结构的IoStatus.Status 成员合适的状态码,例如STATUS_ACCESS_DENIED(STATUS_SUCCESS是不行的)
  3. 设置回调数据结构 IoStatus.Information成员为0
  4. 返回FLT_POSTOP_FINISHED_PROCESSING.

When setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation, the minifilter driver must specify a valid error NTSTATUS value. Note that minifilter drivers cannot specify STATUS_FLT_DISALLOW_FAST_IO; only the filter manager can use this NTSTATUS value.

Callers of FltCancelFileOpen must be running at IRQL <= APC_LEVEL. However, a minifilter driver can safely call this routine from a post-create callback routine, because, for IRP_MJ_CREATE operations, the postoperation callback routine is called at IRQL = PASSIVE_LEVEL, in the context of the thread that originated the create operation. 

同preoperation一样,回调数据结构的IoStatus.Status 不能设置为STATUS_FLT_DISALLOW_FAST_IO,只有驱动管理器能设置这个值

FltCancelFileOpen 的调用级别为IRQL <= APC_LEVEL.。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值