Writing Preoperation and Postoperation Callback Routines

In its DriverEntry routine, a minifilter driver can register up to onepreoperation callback routine and up to onepostoperation callback routine for each type of I/O operation that it needs to filter.

在DriverEntry函数中,一个文件系统过滤驱动可以为其要过滤的每种IO操作至多注册一个preoperation回调函数和至多一个postoperation回调函数。

Unlike a legacy file system filter driver, a minifilter driver can choose which types of I/O operations to filter. 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. The minifilter driver receives only those I/O operations for which it has registered a preoperation or postoperation callback routine.

和传统文件系统过滤驱动不同,minifilter过滤驱动可以选择要处理的IO类型,并且只为其注册preoperation回调函数或者postoperation回调函数。minifilter过滤驱动只会接收它注册的IO类型操作。

A preoperation callback routine is similar to a dispatch routine in the legacy filter driver model. When the filter manager processes an I/O operation, it calls the preoperation callback routine of each minifilter driver in the minifilter driver instance stack that has registered one for this type of I/O operation. The topmost minifilter driver in the stack—that is, the one whose instance has the highest altitude—receives the operation first. When that minifilter driver finishes processing the operation, it returns the operation to the filter manager, which then passes the operation to the next-highest minifilter driver, and so on. When all minifilter drivers in the minifilter driver instance stack have processed the I/O operation—unless a minifilter driver has completed the I/O operation—the filter manager sends the operation to legacy filters and the file system.

preoperation回调函数类似传统文件过滤驱动中的派发函数。驱动管理器在处理IO操作时,它会调用每一个注册这种IO类型的minifilter过滤驱动的preoperation回调函数。最上层的minifilter过滤驱动,也就是谁的实例altitude值最大的那个,最先接收到操作通知。过滤驱动处理完毕后,它将操作返回给过滤管理器,而过滤管理器将操作传递给下一个过滤驱动。如果没有minifilter过滤驱动结束这个IO操作,那么在所有的minifilter驱动实例处理完IO操作后,过滤管理器将操作传递给传统过滤驱动及文件系统。

A postoperation callback routine is similar to a completion routine in the legacy filter driver model. Completion processing for an I/O operation begins when the I/O manager passes the operation to the file system and legacy filters that have registered completion routines for the operation. After these completion routines have finished, the filter manager performs completion processing for the operation. The filter manager then calls the postoperation callback routine of each minifilter driver in the minifilter driver instance stack that has registered one for this type of I/O operation. The bottom minifilter driver in the stack—that is, the one whose instance has the lowest altitude—receives the operation first. When that minifilter driver finishes processing the operation, it returns it to the filter manager, which then passes the operation to the next-lowest minifilter driver, and so on. 

postoperation回调函数类型传统过滤驱动中的完成例程。当传统的文件过滤驱动及文件系统注册的完成例程调用完毕后,过滤管理器为这个IO操作调用minifilter注册的postoperation回调函数。最下层的minifilter(也就是altitude值最小的那个)最先接收到操作。当他完成操作后并返回到过滤管理器后,过滤管理器接着调用altitude值下一个最低的minifilter过滤驱动。


Filtering I/O Operations in a Minifilter Driver

The following list describes several guidelines for filtering specific types of I/O operations in a file system minifilter driver:

以下列表描述了在文件过滤驱动中对于过滤某些类型的IO操作时应遵循的指导原则

  • The preoperation callback routine for IRP_MJ_CREATE cannot query or set contexts for files, streams, or stream handles, because, at pre-create time, the file or stream (if any) that is going to be created has not yet been determined.
  • 对于IRP_MJ_CREATE操作,preoperation回调函数不能查询或者设置文件、流或者流句柄的上下文,因为在预创建的时候,文件及流没有被确定。
  • The postoperation callback routine for IRP_MJ_CLOSE cannot set or query contexts for files, streams, or stream handles, because the system-internal structures that those items are associated with are freed before the post-close routine is called.
  • 对于IRP_MJ_CLOSE操作,postoperation回调函数不能查询或者设置文件、流或者流句柄的上下文,因为在postoperation回调函数被调用之前,那些与这些项关联的系统内部结构已经被释放。
  • Minifilter drivers must never fail IRP_MJ_CLEANUP or IRP_MJ_CLOSE operations. These operations can be pended, returned to the filter manager, or completed with STATUS_SUCCESS. However, a preoperation callback routine must never fail these operations.
  • minifilter驱动必须不能使 IRP_MJ_CLEANUP or IRP_MJ_CLOSE操作失败,这些操作可以被挂起,返回给过滤管理器,或者结束掉,但是preoperation回调函数不能使这些操作失败。
  • Minifilter drivers cannot register a postoperation callback routine for IRP_MJ_SHUTDOWN. 
  • minifilter驱动不能为IRP_MJ_SHUTDOWN注册postoperation回调函数回调函数。

Writing Preoperation Callback Routines

Like a dispatch routine, a preoperation callback routine can be called at IRQL = PASSIVE_LEVEL or at IRQL = APC_LEVEL. Typically it is called at IRQL = PASSIVE_LEVEL, in the context of the thread that originated the I/O request. For fast I/O and file system filter (FsFilter) operations, the preoperation callback routine is always called at IRQL = PASSIVE_LEVEL. However, for an IRP-based operation, a minifilter driver's preoperation callback routine can be called in the context of a system worker thread if a higher filter or minifilter driver pends the operation for processing by the worker thread. 
和派发函数一样,preoperation回调函数在IRQL为passive或者apc时被调用,一般为passive级别,在发起IO操作的线程上下文。快速IO及FsFilter操作类型preoperation回调函数在passive级别被调用。但是对于IRP基础操作,如果上层过滤驱动或者minifilter驱动挂起操作后宫工作线程处理,minifilter preoperation回调函数可以在系统工作线程上下文内调用

When the filter manager calls a minifilter driver's preoperation 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 a status value other than FLT_PREOP_PENDING from the preoperation callback routine. 
Calls FltCompletePendedPreOperation from a work routine that has processed an operation that was pended in the preoperation callback routine. 

当过滤管理器调用minifilter的preoperation回调函数,minifilter驱动就暂时的控制了这个IO操作,minifilter保持这个控制直到其做了以下事:

1. preoperation回调函数返回了除FLT_PREOP_PENDING之外的状态码

2. 从一个工作函数中调用FltCompletePendedPreOperation 完成之前在preoperation回调函数中挂起的操作。


Passing an I/O Operation Down the Minifilter Driver Instance Stack
When a minifilter driver's preoperation callback routine or work routine returns an I/O operation to the filter manager, the filter manager sends the operation to minifilter drivers below the current minifilter driver in the minifilter driver instance stack and to legacy filters and the file system for further processing. 
A minifilter driver's preoperation callback routine returns an I/O operation to the filter manager for further processing by returning one of the following status values: 
FLT_PREOP_SUCCESS_NO_CALLBACK (all operation types) 
FLT_PREOP_SUCCESS_WITH_CALLBACK (all operation types) 
FLT_PREOP_SYNCHRONIZE (IRP-based I/O operations only) 
Note  Although FLT_PREOP_SYNCHRONIZE should be returned only for IRP-based I/O operations, you can return this status value for other operation types. If it is returned for an I/O operation that is not an IRP-based I/O operation, the filter manager treats this return value as if it were FLT_PREOP_SUCCESS_WITH_CALLBACK. 
Alternatively, the work routine for an operation that was pended in a preoperation callback routine returns an I/O operation to the filter manager by passing one of the preceding status values in the CallbackStatus parameter when it calls FltCompletePendedPreOperation to resume processing for the pended I/O operation. 

当minifilter驱动或者工作例程将IO操作返回给过滤管理器后,过滤管理器将IO操作发给下一层过滤驱动及遗留过滤驱动及文件系统进一步处理。

minifilter驱动的 preoperation回调函数返回以下状态码给过滤管理器以进行进一步处理。

FLT_PREOP_SUCCESS_NO_CALLBACK、FLT_PREOP_SUCCESS_WITH_CALLBACK、FLT_PREOP_SYNCHRONIZE 。其中FLT_PREOP_SYNCHRONIZE 只针对IRP-Based IO操作,如果其它类型操作返回了FLT_PREOP_SYNCHRONIZE,过滤管理器将认为其返回了 FLT_PREOP_SUCCESS_WITH_CALLBACK。另外工作例程若调用FltCompletePendedPreOperation结束IO操作,返回码作为CallbackStatus 传递。

Returning FLT_PREOP_SUCCESS_WITH_CALLBACK
If a minifilter driver's preoperation callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK, the filter manager calls the minifilter driver's postoperation callback routine during I/O completion. 
Note  If the minifilter driver's preoperation callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK but the minifilter driver has not registered a postoperation callback routine for the operation, the system asserts on a checked build. 
If the minifilter driver's preoperation callback routine returns FLT_PREOP_SUCCESS_WITH_CALLBACK, it can return a non-NULL value in its CompletionContext output parameter. This parameter is an optional context pointer that is passed to the corresponding postoperation callback routine. The postoperation callback routine receives this pointer in its CompletionContext input parameter. 
The FLT_PREOP_SUCCESS_WITH_CALLBACK status value can be returned for all types of I/O operations. 

如果 preoperation回调函数返回了 FLT_PREOP_SUCCESS_WITH_CALLBACK,filter Manager在处理IO完成时调用postoperation 回调函数,如果minifilter没有注册postoperation 回调函数,在Checked版本中会触发断言。并且若preoperation回调函数返回了 FLT_PREOP_SUCCESS_WITH_CALLBACK,它可以为输出参数CompletionContext 返回一个非空值,这个参数是可选的并且其会被作为参数传递到postoperation 回调函数(参数CompletionContext )。任何类型的IO操作都可以返回FLT_PREOP_SUCCESS_WITH_CALLBACK。

Returning FLT_PREOP_SUCCESS_NO_CALLBACK
If a minifilter driver's preoperation callback routine returns FLT_PREOP_SUCCESS_NO_CALLBACK, the filter manager does not call the minifilter driver's postoperation callback routine, if one exists, during I/O completion. 
If the minifilter driver's preoperation callback routine returns FLT_PREOP_SUCCESS_NO_CALLBACK, it must return NULL in its CompletionContext output parameter. 
The FLT_PREOP_SUCCESS_NO_CALLBACK status value can be returned for all types of I/O operations. 

如果 preoperation回调函数返回了 FLT_PREOP_SUCCESS_NO_CALLBACK,filter Manager在处理IO完成时不会调用postoperation 回调函数,并且必须为输出参数CompletionContext 返回NULL。任何类型的IO操作都可以返回FLT_PREOP_SUCCESS_NO_CALLBACK。

Returning FLT_PREOP_SYNCHRONIZE
If a minifilter driver's preoperation callback routine synchronizes an I/O operation by returning FLT_PREOP_SYNCHRONIZE, the filter manager calls the minifilter driver's postoperation callback routine during I/O completion. 
The filter manager calls the minifilter driver's postoperation callback routine in the same thread context as the preoperation callback, at IRQL <= APC_LEVEL. (Note that this thread context is not necessarily the context of the originating thread.) 
Note  If the minifilter driver's preoperation callback routine returns FLT_PREOP_SYNCHRONIZE, but the minifilter driver has not registered a postoperation callback routine for the operation, the system asserts on a checked build. 
If the minifilter driver's preoperation callback routine returns FLT_PREOP_SYNCHRONIZE, it can return a non-NULL value in its CompletionContext output parameter. This parameter is an optional context pointer that is passed to the corresponding postoperation callback routine. The postoperation callback routine receives this pointer in its CompletionContext input parameter. 
A minifilter driver's preoperation callback routine should return FLT_PREOP_SYNCHRONIZE only for IRP-based I/O operations. However, this status value can be returned for other operation types. If it is returned for an I/O operation that is not an IRP-based I/O operation, the filter manager treats this return value as if it were FLT_PREOP_SUCCESS_WITH_CALLBACK. To determine whether an operation is an IRP-based I/O operation, use the FLT_IS_IRP_OPERATION macro. 
Minifilter drivers should not return FLT_PREOP_SYNCHRONIZE for create operations, because these operations are already synchronized by the filter manager. If a minifilter driver has registered preoperation and postoperation callback routines for IRP_MJ_CREATE operations, the post-create callback routine is called at IRQL = PASSIVE_LEVEL, in the same thread context as the pre-create callback routine. 
Minifilter drivers must never return FLT_PREOP_SYNCHRONIZE for asynchronous read or write operations. Doing so can severely degrade both minifilter driver and system performance and can even cause deadlocks if, for example, the modified page writer thread is blocked. Before returning FLT_PREOP_SYNCHRONIZE for an IRP-based read or write operation, a minifilter driver should verify that the operation is synchronous by calling FltIsOperationSynchronous. 
The following types of I/O operations cannot be synchronized: 
Oplock file system control (FSCTL) operations (MajorFunction is IRP_MJ_FILE_SYSTEM_CONTROL; FsControlCode is FSCTL_REQUEST_FILTER_OPLOCK, FSCTL_REQUEST_BATCH_OPLOCK, FSCTL_REQUEST_OPLOCK_LEVEL_1, or FSCTL_REQUEST_OPLOCK_LEVEL_2.) 
Notify change directory operations (MajorFunction is IRP_MJ_DIRECTORY_CONTROL; MinorFunction is IRP_MN_NOTIFY_CHANGE_DIRECTORY.) 
Byte-range lock requests (MajorFunction is IRP_MJ_LOCK_CONTROL; MinorFunction is IRP_MN_LOCK.) 
FLT_PREOP_SYNCHRONIZE cannot be returned for any of these operations. 

如果 preoperation回调函数返回了 FLT_PREOP_SYNCHRONIZE,过滤管理器将会在Apc级别调用minifilter驱动的postoperation回调函数,并且和preoperation回调函数处于同一线程上下文。如果minifilter没有注册postoperation 回调函数,在Checked版本中会触发断言。为了判断一个IO操作是否为IPR-based, 请使用宏 FLT_IS_IRP_OPERATION。不要为IRP_MJ_CREATE操作返回FLT_PREOP_SYNCHRONIZE,因为其本身已被过滤管理器同步,如果注册了postoperation回调函数,则postoperation回调函数处于passive级别,并且线程上下文与preoperation回调函数相同。

minifilter驱动不应该为异步读写返回FLT_PREOP_SYNCHRONIZE,这样会严重的影响系统性能并且可能死锁,例如????,在为读写操作返回FLT_PREOP_SYNCHRONIZE之前,minifilter驱动应该调用FltIsOperationSynchronous来验证操作是同步的。

以下类型的IO操作是不能同步的:

Oplock file system control (FSCTL) operations (MajorFunction is IRP_MJ_FILE_SYSTEM_CONTROL; FsControlCode is FSCTL_REQUEST_FILTER_OPLOCK, FSCTL_REQUEST_BATCH_OPLOCK, FSCTL_REQUEST_OPLOCK_LEVEL_1, or FSCTL_REQUEST_OPLOCK_LEVEL_2.) 
Notify change directory operations (MajorFunction is IRP_MJ_DIRECTORY_CONTROL; MinorFunction is IRP_MN_NOTIFY_CHANGE_DIRECTORY.) 
Byte-range lock requests (MajorFunction is IRP_MJ_LOCK_CONTROL; MinorFunction is IRP_MN_LOCK.) 

To complete an I/O operation means to halt processing for the operation, assign it a final NTSTATUS value, and return it to the filter manager.

When a minifilter driver completes an I/O operation, the filter manager does the following:

  • Does not send the operation to minifilter drivers below the current minifilter driver, to legacy filters, or to the file system.
  • Calls the postoperation callback routines of the minifilter drivers above the current minifilter driver in the minifilter driver instance stack.
  • Does not call the current minifilter driver's postoperation callback routine for the operation, if one exists.

A minifilter driver's preoperation callback routine completes an I/O operation by performing the following steps:

  1. Setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation.
  2. Returning FLT_PREOP_COMPLETE.

完成IO操作意味着中断IO处理,赋给操作最终的状态码并返回给过滤驱动器

当minifilter驱动完成一个IO操作时,过滤管理器执行以下动作

  • 不再将操作发给下层过滤驱动,遗留过滤驱动及文件系统
  • 调用上层minifilter过滤驱动的postoperation回调函数
  • 不调用当前minifilter过滤驱动的postoperation回调函数。

minifilter过滤驱动执行以下动作完成一个IO操作

  1. 设置callback data structure中IoStatus.Status 成员最后的NTSTATUS值
  2. 返回FLT_PREOP_COMPLETE.

A preoperation callback routine that completes an I/O operation cannot set a non-NULL completion context (in the CompletionContext output parameter).

完成IO操作的preoperation回调函数不能给输出参数CompletionContext 设置一个非空的完成上下文。

A minifilter driver can also complete an operation in the work routine for a previously pended I/O operation by performing the following steps:

  1. Setting the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation.
  2. Passing FLT_PREOP_COMPLETE in the CallbackStatus parameter when the work routine calls FltCompletePendedPreOperation.

对于之前挂起的IO操作,minifilter驱动可以执行以下动作完成一个IO操作

  1. 设置callback data structure中IoStatus.Status 成员最后的NTSTATUS值
  2. 工作例程调用FltCompletePendedPreOperation时给参数CallbackStatus 传递FLT_PREOP_COMPLETE。

When completing an I/O operation, a minifilter driver must set the callback data structure's IoStatus.Status field to the final NTSTATUS value for the operation, but this NTSTATUS value cannot be STATUS_PENDING or STATUS_FLT_DISALLOW_FAST_IO. For a cleanup or close operation, the field must be STATUS_SUCCESS. These operations cannot be completed with any other NTSTATUS value.

Completing an I/O operation is often referred to as succeeding or failing the operation, depending on the NTSTATUS value:

  • To succeed an I/O operation means to complete it with a success or informational NTSTATUS value, such as STATUS_SUCCESS.
  • To fail an I/O operation means to complete it with an error or warning NTSTATUS value, such as STATUS_INVALID_DEVICE_REQUEST or STATUS_BUFFER_OVERFLOW. 
当完成一个IO操作时,minifilter驱动必须设置callback data structure中 IoStatus.Status ,但是值不能为STATUS_PENDING or STATUS_FLT_DISALLOW_FAST_IO.对于cleanup or close操作,值必须为STATUS_SUCCESS。

In certain circumstances, a minifilter driver might choose to disallow a fast I/O operation instead of completing it. Disallowing a fast I/O operation prevents the fast I/O path from being used for the operation.

在某些情况下,minifilter驱动可以选择不准fast IO操作而不是完成它。不准fast IO操作阻止为这个操作使用fast IO路径。

Like completing an I/O operation, disallowing a fast I/O operation means to halt processing on it and return it to the filter manager. However, disallowing a fast I/O operation is different from completing it. If a minifilter driver disallows a fast I/O operation that was issued by the I/O manager, the I/O manager may reissue the same operation as an equivalent IRP-based operation.

When a minifilter driver's preoperation callback routine disallows a fast I/O operation, the filter manager does the following:

  • Does not send the operation to minifilter drivers below the current minifilter driver, to legacy filters, or to the file system.
  • Calls the postoperation callback routines of the minifilter drivers above the current minifilter driver in the minifilter driver instance stack.
  • Does not call the current minifilter driver's postoperation callback routine for the operation, if one exists.

不准fast IO操作意味着终止IO操作,但是不准fast IO操作与完成操作不同。如果minifilter驱动不准 IO Manager发起的fast IO操作,IOmanager可能重新发起一个相同的IRP-based IO 操作。

A minifilter driver disallows a fast I/O operation by returning FLT_PREOP_DISALLOW_FASTIO from the preoperation callback routine for the operation.

minifilter驱动返回 FLT_PREOP_DISALLOW_FASTIO 表示不准fast IO操作。

The preoperation callback routine should not set the callback data structure's IoStatus.Status field, because the filter manager automatically sets this field to STATUS_FLT_DISALLOW_FAST_IO.

FLT_PREOP_DISALLOW_FASTIO can only be returned for fast I/O operations. To determine whether an operation is a fast I/O operation, see FLT_IS_FASTIO_OPERATION.

Minifilter drivers cannot return FLT_PREOP_DISALLOW_FASTIO for IRP_MJ_SHUTDOWN, IRP_MJ_VOLUME_MOUNT, or IRP_MJ_VOLUME_DISMOUNT operations. 

preoperation回调函数如果返回FLT_PREOP_DISALLOW_FASTIO ,那么不应该再去设置IoStatus.Status ,因为过滤管理器会自动的设置IoStatus.Status 为STATUS_FLT_DISALLOW_FAST_IO。FLT_PREOP_DISALLOW_FASTIO只能为fast IO操作返回值,判断一个操作是否为fast IO,使用FLT_IS_FASTIO_OPERATION。

minifilter驱动不能为 IRP_MJ_SHUTDOWN, IRP_MJ_VOLUME_MOUNT, or IRP_MJ_VOLUME_DISMOUNT 返回FLT_PREOP_DISALLOW_FASTIO。


A minifilter driver's preoperation callback routine can pend an I/O operation by posting the operation to a system work queue and returning FLT_PREOP_PENDING. Returning this status value indicates that the minifilter driver is retaining control of the I/O operation until it calls FltCompletePendedPreOperation to resume processing for the I/O operation.

A minifilter driver's preoperation callback routine pends an I/O operation by performing the following steps:

  1. Posting the I/O operation to a system work queue by calling a routine such as FltQueueDeferredIoWorkItem.
  2. Returning FLT_PREOP_PENDING.

minifilter驱动的preoperation回调函数可以将操作发送到系统工作队列挂起一个IO操作并返回FLT_PREOP_PENDING,返回这个状态码意味着IO 操作被此minifilter驱动控制,直到调用FltCompletePendedPreOperation 继续IO操作。

minifilter驱动执行以下动作挂起IO操作

  1. 将IO操作发送至系统队列,例如调用FltQueueDeferredIoWorkItem
  2. 返回FLT_PREOP_PENDING.

A minifilter driver that must pend all (or most) incoming I/O operations should not use routines such as FltQueueDeferredIoWorkItem to pend operations, because calling this routine can cause the system work queues to be flooded. Instead, such a minifilter driver should use a cancel-safe queue. For more information about using cancel-safe queues, see FltCbdqInitialize.

minifilter驱动如果要挂起所有的IO操作,那么不应该调用FltQueueDeferredIoWorkItem 。因为这样会使系统队列溢出。对于这样的驱动应该使用cancel-safe队列。对于如何使用cancel-safe队列,参考FltCbdqInitialize

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, see IoGetTopLevelIrp.)
  • The target instance for the I/O operation is being torn down.

在以下情况下FltQueueDeferredIoWorkItem 将调用失败

  • 操作不是IRP-based 操作
  • 操作时paging IO操作
  • 当前线程的TopLevelIrp非空
  • 目标实例正在被拆卸

If the minifilter driver's preoperation callback routine returns FLT_PREOP_PENDING, it must return NULL in the CompletionContext output parameter.

A minifilter driver can return FLT_PREOP_PENDING only for IRP-based I/O operations. To determine whether an operation is an IRP-based I/O operation, use the FLT_IS_IRP_OPERATION macro.

The work routine that dequeues and processes the I/O operation must call FltCompletePendedPreOperation to resume processing for the operation.  

如果preoperation回调函数返回FLT_PREOP_PENDING,输出参数 CompletionContext 必须为NULL。minifilter驱动只能为IRP-based IO操作返回FLT_PREOP_PENDING,判断操作是否为IRP-based,使用宏FLT_IS_IRP_OPERATION 。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值