XiangXiangRen
总版主
总版主
  • 注册日期2003-02-22
  • 最后登录2015-09-01
  • 粉丝13
  • 关注0
  • 积分1042分
  • 威望472点
  • 贡献值1点
  • 好评度145点
  • 原创分13分
  • 专家分1分
阅读:2030回复:1

微过滤器驱动开发指南 之二

楼主#
更多 发布于:2005-06-20 22:50
6.实例的通知

当一个实例生成的时候,一组回调函数提供来通知微过滤器。通过这些回调,微过滤器可以决定它的实例在什么时候绑定到卷上和从卷上解除了绑定。

6.1. 安装一个实例

回调例程InstatanceSetupCallback()在下列情况下被调用:
.当一个微过滤器加载的时候,每个存在的卷都会导致这个调用。
.当一个新的卷被mount.
.当FltAttachVolume被调用(内核模式)
.当FltAttachVolumeAtAltitude()被调用(内核模式)
.当FilterAttach()被调用(用户模式)
.当FilterAttachAtAltitude()被调用(用户模式)

在这个过程中,微过滤器决定是否在这个卷上生成实例。这个回调的原型如下:
typedef NTSTATUS
(*PFLT_INSTANCE_SETUP_CALLBACK) (
    IN PCFLT_RELATED_OBJECTS FltObjects,
    IN FLT_INSTANCE_SETUP_FLAGS Flags,
    IN DEVICE_TYPE VolumeDeviceType,
    IN FLT_FILESYSTEM_TYPE VolumeFilesystemType
);
FltObjects结构喊有指向微过滤器,卷,和实例的指针。这个实例指将要在InstanceSetupCallback()函数中生成的实例。Flags标记是什么操作导致激发了InstanceSetupCallback():
FLTFL_INSTANCE_SETUP_AUTOMATIC_ATTACHMENT:  这是一个微过滤器注册的时候,一个自动的绑定通知。过滤管理器为每个刚加载的微过滤器枚举所有的卷。如果是一个使用者明确的指定一个实例绑定到某一个卷,不会设置有这个标记。
FLTFL_INSTANCE_SETUP_MANUAL_ATTACHMENT:  通过调用FilterAttach()(用户态),或者是FilterAttachVolumeAtAltitude()(用户态),或者是FltAttachVolume()(内核态)所发起的一个手工的请求。
FLTFL_INSTANCE_SETUP_NEWLY_MOUNTED_VOLUME:  文件系统刚刚挂载(mount)了一个卷,所以呼叫InstanceSetupCallback()来通知微过滤器,如果它愿意可以生成实例来绑定这个卷。

在InstanceSetupCallback()中,微过滤器同时得到了卷设备类型(VolumeDeviceType)和卷文件系统类型(VolumeFilesytemType),用以判断这个卷是否过滤器所感兴趣的。同时,微过滤器可以调用FltGetVolumeProperties()来获取卷属性。通过FltSetInstanceContext()在实例上设置上下文。当然这是需要绑定的时候。它甚至可以在卷上打开或者关闭文件。

如果这个回调返回了成功,那么这个实例将绑定到卷上。如果返回了一个警告或者错误,那么不会绑定。
如果微过滤器没有指定InstanceSetup回调,那么,系统将认为用户总是返回了STATUS_SUCCESS,实例总是会生成并绑定。

6.2. 控制实例的销毁

InstanceQueryTeardown()回调仅仅在一个手工解除绑定的请求下被调用。以下操作可能导致:
FltDetachVolume() (内核模式)
FilterDetach()    (用户模式)

如果一个微过滤器没有提供这个回调,那么手工解除绑定是不被支持的。但是,卷的解挂载(dismount)和微过滤器的卸载还是允许的。

如果这个回调返回成功,那么过滤管理器开始销毁给出的实例。最后实例的InstanceTeardownStart()和InstanceTeardownComplete()会被调用。如果返回了错误或者警告,手工解除绑定会失败。推荐的错误代码有: STATUS_FLT_DO_NOT_DETACH,不过实际上你可以返回任何错误代码。
InstanceQueryTeardown()回调的原型是:
typedef NTSTATUS
(*PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK) (
    IN PCFLT_RELATED_OBJECTS FltObjects,
    IN FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
    );
和InstanceSetupCallback()类似,FltObject指出了与这个销毁操作有关的微过滤器,卷和实例。

6.3. 实例解绑定的同步

如果InstanceTeardownStart()的时候已经决定要解除绑定,那么这个例程中必须做以下的事情:
(1)重设所有的未决的I/O操作(包括预操作和后操作)
(2)保证不会有新的I/O操作进入未决。
(3)对刚刚到达的操作开始最少的工作。
同时,应该做以下操作:
(1)关闭所有打开的文件。
(2)取消所有本过滤器发起的I/O请求。
(3)停止将新的工作任务排队。

然后微过滤器把控制权交还过滤管理器来继续它的销毁过程。当所有与这个实例相关的操作都排除干净或者完成了,InstanceTeardownComplete()会被调用。管理器保证此时所有此实例的存在的操作回调都完成了。这时微过滤器必须关闭所有这个实例打开的文件。
这两个回调的原型如下:
typedef VOID
(*PFLT_INSTANCE_TEARDOWN_CALLBACK) (
    IN PCFLT_RELATED_OBJECTS FltObjects,
IN FLT_INSTANCE_TEARDOWN_FLAGS Reason
);
FltObjets中有微过滤器,卷和实例。Resson参数指明这次销毁的原因,可能是以下一些标记的组合:
FLTFL_INSTANCE_TEARDOWN_MANUAL:  这次销毁操作是一个手工的请求。(FilterDetach()或者 FltDetachVolume()).
FLTFL_INSTANCE_TEARDOWN_FILTER_UNLOAD:  这次销毁操作是因为微过滤器执行卸载或者是选择了把卸载请求失败掉导致的。
FLTFL_INSTANCE_TEARDOWN_MANDATORY_FILTER_UNLOAD:  这次销毁操作是一次强制卸载导致的。这种情况下不能把卸载请求失败掉。
FLTFL_INSTANCE_TEARDOWN_VOLUME_DISMOUNT: 这次销毁是一个卷被解挂载的结果。FLTFL_INSTANCE_TEARDOWN_INTERNAL_ERROR:  这次销毁是因为安装实例的时候的一个内部错误导致的,比如内存不足。

请注意没有返回值。InstanceTeardownStart()和InstanceTeardownComplete()都不能失败。过滤管理器保证这些例程都运行在Passive IRQL.

7.回调支持

7.1 回调数据(Callback data)

回调数据(Callback data)是过滤管理器用来描述I/O操作的新结构。类似旧过滤模型下的IRP.微过滤器通过这个结构和过滤管理器交互。不同的是,回调数据不像IRP那样管理一个栈结构。回调数据的管理都通过已经明确定义的过滤管理器接口。并且返回状态值给过滤管理器即可。
FLT_CALLBACK_DATA类型包含了微过滤器描述一个I/O操作所需要的所有的信息。下面继续详细讲解这个结构中的各个域来说明其中包含的信息:
Flags:提供这个操作的一些信息。一个或多个下面的标记可能被设置在Flags中:
FLTFL_CALLBACK_DATA_IRP_OPERATION: 这个回调数据描述一个IRP操作。
FLTFL_CALLBACK_DATA_FAST_IO_OPERATION:这个回调数据描述一个FastIO操作。
FLTFL_CALLBACK_DATA_FS_FILTER_OPERATION:这个回调描述一个文件系统过滤器操作。
FLTFL_CALLBACK_DATA_SYSTEM_BUFFER:这个操作所用的缓冲是一个系统分配的缓冲。
FLTFL_CALLBACK_DATA_GENERATED_IO:这个操作是由一个微过滤器发起的。
FLTFL_CALLBACK_DATA_REISSUED_IO:这个操作被一个当前实例之上的过滤器所重新发回给文件系统。
FLTFL_CALLBACK_DATA_DRAINING_IO:只有设置了后操作(Post-operation)回调的情况下,表明这是一个快速“排出”的I/O操作以便微过滤器的卸载。
FLTFL_CALLBACK_DATA_POST_OPERATION:只有设置了后操作(Post-operation)回调的情况下,表明着个I/O正在后操作中。
FLTFL_CALLBACK_DATA_DIRTY:当一个微过滤器已经改变了这个操作的一个或者多个可变参数的时候,设置这个参数。这个标记仅仅在Pre-operation过程中设置。微过滤器必须用FLT_SET_CALLBACK_DATA_DIRTY()和FLT_CLEAR_CALLBACK_DATA_DIRTY()来操作这个标记。
Thread: 发出这个操作的线程的地址。
Iopb:       指向这个操作的可变参数的指针。这个结构在后边详叙。
IoStatus:IO_STATUS_BLOCK结构返回操作最后的状态。如果一个微过滤器打算结束这个操作,那么必须先设置这个域,然后才能结束这个请求。对于传递给文件系统去的请求,在后操作过程(Post-operation)中有操作最终的状态。
TagData:仅仅在Create操作的后操作回调中有效。当一个操作的目标文件有一个重解析点(Reparse point)的时候设置这个位。
QueueLinks:一个链表入口结构。有时要把回调数据(Callback Data)放入工作队列中使用这个。
QueueContext[2]:一组空指针结构,用来传入附加的上下文到工作队列处理过程中。
FilterContext[4]:一组空指针结构,当回调数据进入了队列,微过滤器可以做任意使用。不依赖于过滤管理器的内部结构。
RequestorMode:这个操作的者的请求模式。

Iopb域所指的是一个FLT_IO_PARAMETER_BLOCK结构。包含了回调数据中可以修改的部分。对比IRP来说,这里相当于IRP的当前栈空间(current stack location)。微过滤器必须访问这个结构来得到每次预操作(pre-operation)和后操作(post-operation)回调的I/O参数。下面是一些更详细的细节:
IrpFlags:IRP中描述这个操作的一些标记。
MajorFunction:IRP主功能号。
MinorFunction:IRP辅功能号。
OperationFlags:即IO_STACK_LOCATION.Flags.
TargetFileObject:这个操作所影响到的目标文件。
TargetInstance:管理这个操作的实例。
Parameters:FLT_PARAMETERS是一个共用体。描述主功能号和辅功能号所指定的操作的具体参数。

除了在预操作回调中不能修改主功能号之外,微过滤器可以修改这个结构中其他的任何参数。如果参数改变,微过滤器应该调用FLT_SET_CALLBACK_DIRTY()来注明这个改变。更多详细的信息将在第8节中讲述。

微过滤器在同一个I/O操作的预回调和后回调中,总是会看到参数是一样的。即使下面的过滤器可能已经修改了这些参数。这是由过滤管理器保证的。但是虽然FLT_IO_PARAMTER_BLOCK的内容是一样的,在预操作和后操作中,这个结构的地址可能不一样。因此微过滤器不应该依赖这个地址。

回调数据结构包含IO_STATUS_BLOCK来记录这个操作的状态。过滤管理器会“尊重”这些改变而不会标记这些数据为脏(Dirty)。微过滤器如果打算在预操作回调中结束这个操作或者是后操作回调中撤消这个操作,都必须先设置这个IO_STATUS_BLOCK。

7.2 预操作回调(Pre-Operation Callbacks)

所有的预操作回调原型都是这样:
typedef FLT_PREOP_CALLBACK_STATUS
(*PFLT_PRE_OPERATION_CALLBACK) (
    IN OUT PFLT_CALLBACK_DATA Data,
    IN PCFLT_RELATED_OBJECTS FltObjects,
    OUT PVOID *CompletionContext
);
所有的预操作回调都返回一个FLT_PRE_OPERATION_CALLBACK_STATUS.这个变量是如下定义的:
FLT_PREOP_SUCCESS_WITH_CALLBACK:这个操作成功了而且微过滤器需要后操作回调。
FLT_PREOP_SUCCESS_NO_CALLBACK:       操作成功了,但是不需要后操作回调。
FLT_PREOP_PENDING:              微过滤器将在未来某个时候结束这个操作(通过调用FltCompletePendedOperation())。微过滤器在返回这个值之前不需要做其他特殊的操作(比如IoMarkIrpPending())。如果这个状态返回了,这个I/O操作被过滤管理器挂起(栈中的下层驱动都不会收到预操作回调),直到FltCompletePendedPreOperation()被调用。
FLT_PREOP_COMPLETE:              微过滤结束了操作。这个微过滤器设置了Data->IoStatus.Status中的I/O状态。这个过滤器以下的微过滤器,旧模型过滤器和文件系统都不会看见这个I/O请求。而之上的微过滤器回看到这个请求以合适的状态完成。对于CLEANUP和CLOSE操作来说,微过滤器以一个失败状态结束这个操作是不允许的。因为这些操作不能失败。
FLT_PREOP_SYNCHRONIZE:              仅仅在非CREATE操作有效。(CREATE操作是自动同步的)。若返回此值微过滤器必须有一个后操作回调。这表明这个微过滤器希望这个操作在同一个线程里完成。也就是说后操作调出现的时候和预操作调用在同一个线程上下文里。这是由过滤管理器所保证的。不管下层的过滤器以及文件系统是挂起还是忽略这个I/O操作。这个状态必须小心使用。因为过滤管理器必须同步整个I/O,这可能影响整个系统的性能。
FLT_PREOP_DISALLOW_FAST_IO:       这个状态仅仅在旧模型下返回BOOLEAN的fastI/O的操作的情况下有效。这个状态表明不接受fastI/O请求,请发送IRP重试。

在预操作返回之前,过滤器可能修改I/O操作的参数。而且能修改的参数都集中在Data->Iopb中。当一个微过滤器修改了任何一个参数,它必须调用FLT_SET_CALLBACK_DATA_DIRTY(),否则,修改不会被承认,可能导致未知的错误。

对此还有两个例外。如果修改的是IoStatus,没有必要设置Dirty就会被过滤管理器所承认。
另一个例外是IRP_MJ_CREATE的后操作过程。如果一个碰到重解析点(reparse point),Data->TagData会指想一个重解析数据缓冲。如果微过滤器打算修改这个缓冲,它可以释放了这个缓冲然后重新分配一个(不能为空)。此时不用调用FLT_SET_CALLBACK_DATA_DIRTY().

7.3 后操作回调(Post-Operation Callbacks)

所有的后操作都有同样的原型:
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
);
Data->Flags中都设置了FLTFL_CALL_DATA_POST_OPERATION.
如果一个微过滤器在预操作回调中返回FLT_PREOP_SUCCESS_WITH_CALLBACK了,它肯定能收到这个同样操作的完成回调也就是后操作回调。后操作回调返回的类型为FLT_POSTOP_CALLBACK_STATUS.这个值是:
FLT_POSTOP_FINISHED_PROCESSING
harry_chen
驱动牛犊
驱动牛犊
  • 注册日期2002-07-08
  • 最后登录2007-05-25
  • 粉丝0
  • 关注0
  • 积分31分
  • 威望4点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2005-06-21 08:55
先拷下来慢慢看!:)
学而不思则罔,思而不学则殆 学而思之,思而学之,岂非圣人乎?
游客

返回顶部