文件系统Minifilter驱动(二)

来源:互联网 发布:织梦cms视频教程下载 编辑:程序博客网 时间:2024/05/01 20:33

二、Filter管理器模型的优势

Filter管理器模型在现有的legacy过滤驱动模型之上提供了以下优势:

 

比filter加载顺序更易控制. 不像legacy过滤驱动,一个minifilter驱动可以在任何时候被加载且因其altitude被绑定到合适的位置。

在系统运行期间的卸载能力. 不像在系统运行期间不能被卸载的legacy过滤驱动,minifilter驱动能在任意时间被卸载且必要时它能阻止它自己被卸载。Filter管理器同步所有minifilter驱动绑定体的安全移除,且它会处理minifilter驱动被卸载之后完成的操作。

仅需处理必要操作的能力. Filter管理器使用callback模型,在这个模型中minifilter驱动可以挑选要过滤的I/O操作的类型(基于IRP的, fast I/O或FSFilter)。Minifilter驱动只接收它已经为其注册了callback例程的I/O操作。Minifilter驱动可以注册一个唯一的pre-oper或post-oper callback例程,或两者都注册,它可以忽略某些类型的操作,比如分页I/O和缓存的I/O。

内核栈的应用更加高效. Filter管理器被优化为减少了它所使用的内核栈的数量,callback模型也大大减少了栈上的minifilter驱动之间的冲突。Filter管理器通过支持filter初始化的I/O(这仅能被栈中lower驱动看见)减少了递归I/O的冲突。

冗余代码更少. Filter管理器用多种方法减少了minifilter驱动所必需的代码量,比如提供名产生操作的下部构造和为多个minifilter驱动的使用缓存文件名。 Filter管理器绑定卷并通知minifilter驱动什么时候卷可用。Filter管理器被优化为支持多处理器系统,这使得锁定更高效且更低错误的可能性。

简化了复杂部分. Filter管理器通过为一般功能(像命名,上下文管理,在用户模式和内核模式之间通信,屏蔽文件系统的不同)提供支持例程简化了I/O请求的过滤。Filter管理器代表minifilter驱动处理某些任务,比如 pending IRP和枚举并绑定到文件系统栈。

更易于添加新操作. 因为minifilter驱动仅为其将要处理的I/O操作注册,对新操作的支持可以在不破坏现有minifilter驱动的前提下被添加到filter管理器中。 

对多个平台的更好支持. Minifilter驱动可以运行在支持filter管理器的一切版本的Windows上。如果某个minifilter驱动为一个在运行时不可用的I/O操作注册了,则filter管理器只是不对该操作调用minifilter驱动。Minifilter驱动可以以程序的方式决定函数是否可用,filter管理器结构被设计为可扩展的。

对用户模式应用程序的更好支持. Filter管理器为与minifilter驱动一起工作的用户模式服务及控制程序提供一般功能。Filter管理器用户模式库, Filterlib.dll, 激活了用户模式服务或控制程序同minifilter驱动之间的通信。Filterlib.dll 也为管理工具提供了接口。

 

三、Minifilter驱动的Filter管理器支持

本节描述filter管理器为minifilter驱动执行的一般任务提供的支持:

1). Loading and Unloading

Minifilter驱动能在系统运行期间的任意时刻被加载。如果minifilter驱动的INF file 指定其驱动启动类型为SERVICE_BOOT_START, SERVICE_SYSTEM_START或SERVICE_AUTO_START中的一个,那么minifilter驱动的加载就会依照现有的FSFD加载顺序组定义来支持与legacy过滤驱动间的互用性。在系统运行期间,minifilter能通过一个服务启动请求(sc start, net start或者服务APIs)或通过一个外部的加载请求(fltmc load, FltLoadFilter或FilterLoad) 被加载。

 

当minifilter驱动被加载时,它的DriverEntry 例程会被调用,因此minifilter驱动可以执行将应用于该minifilter驱动的所有实例的初始化操作。在它的DriverEntry 例程中它调用FltRegisterFilter来向filter管理器注册callback例程,调用FltStartFiltering来通知filter管理器它已经准备好开始绑定到卷并过滤I/O请求了。

 

Minifilter驱动实例在INF file被定义来用于安装这个minifilter驱动。Minifilter驱动的 INF文件必须定义一个默认实例,它也可以定义额外的实例。这些定义适用于所有的卷。每一个实例的定义都包括实例名,它的altitude和表示这个实例是否可以被自动地、手动地或二者都有地绑定的标记。默认实例用于顺序化minifilter驱动以便filter管理器能以正确的顺序调用minifilter驱动的挂载和实例setup例程。当调用者不指定一个实例名时也用外在的绑定请求来使用默认实例。

 

在卷挂载后,Filter管理器在首个create操作上调用它的InstanceSetupCallback例程来自动地通知minifilter驱动有一个可用卷。当filter管理器在系统启动时枚举现有卷时,这会在FltStartFiltering返回之前发生。当某个卷被挂载或作为一个外部绑定请求 (fltmc attach, FltAttachVolume或FilterAttach)的结果时,那也会在运行时期间发生。

 

当minifilter驱动被卸载,其所绑定的卷被停止或作为一个外部断开请求(fltmc detach, FltDetachVolume或FilterDetach)的结果时,一个minifilter驱动实例会被拆卸。如果minifilter驱动注册了一个InstanceQueryTeardownCallback 例程,它可以通过调用FilterDetach或FltDetachVolume来令一个外部断开请求失败。拆卸的过程如下: 

 

如果minifilter驱动注册了一个InstanceTeardownStartCallback callback例程,那么filter管理器就会在这个过程的开始调用它。在此例程汇中,minifilter驱动应该完成所有未决操作,取消或完成其他工作(比如由minifilter驱动产生的I/O请求和停止队列化新的工作项)。

 

在实例拆卸期间,一切当前正在执行的pre-oper或post-oper callback 例程继续正常的处理,一切正在等待post-oper callback的I/O操作会被"耗尽" 或取消,一切由minifilter驱动产生的I/O操作继续正常的处理直到它们被完成。

 

如果minifilter驱动注册了一个InstanceTeardownCompleteCallback 例程,  filter管理器在所有未决I/O操作已经完成之后调用该例程。在此例程中,minifilter 驱动关闭一切仍然在open的文件。 

 

在实例的所有未决引用都被消耗之后,filter管理器删除残存的context而实例也完全被拆卸。

 

在系统正在运行时,minifilter驱动能通过一个服务停止请求(sc stop, net stop或服务APIs)或通过一个外部卸载请求(fltmc unload, FltUnloadFilter或FilterUnload)被卸载. 

 

Minifilter驱动的FilterUnloadCallback 例程在minifilter驱动卸载时被调用。此例程关闭一切open通信服务器端口,调用FltUnregisterFilter并执行一切需要的清除。该例程的注册是可选的。不过,如果minifilter驱动没有注册一个FilterUnloadCallback 例程, 则minifilter驱动不能被卸载.更多此例程的信息可参考Writing a FilterUnloadCallback Routine

 

用于加载和卸载Minifilter驱动的Filter管理器例程 

 

Filter管理器为外部的加载和卸载请求提供了以下支持例程(可从用户模式或内核模式发出):

 

FilterLoad 

FilterUnload 

FltLoadFilter 

FltUnloadFilter 

以下例程用于为实例的setup和拆卸而注册和注销callback例程: 

 

FltRegisterFilter 

FltStartFiltering 

FltUnregisterFilter 

 

用于实例setup,拆卸和卸载的Minifilter驱动Callback例程

 

以下minifilter驱动callback例程存储于FLT_REGISTRATION 结构之中,这个结构作为一个参数被传给FltRegisterFilter: 

 

Callback例程名

Callback例程类型

InstanceSetupCallback

PFLT_INSTANCE_SETUP_CALLBACK 

InstanceQueryTeardownCallback

PFLT_INSTANCE_QUERY_TEARDOWN_CALLBACK 

InstanceTeardownStartCallback

PFLT_INSTANCE_TEARDOWN_CALLBACK 

InstanceTeardownCompleteCallback

PFLT_INSTANCE_TEARDOWN_CALLBACK 

FilterUnloadCallback

PFLT_FILTER_UNLOAD_CALLBACK 

 

2).处理I/O操作

Filter管理器简化了minifilter驱动对I/O操作的处理。legacy过滤驱动必须正确地将所有I/O请求都传给下一lower驱动并正确地处理pending请求,同步和I/O完成而不论它有没有做该请求相关的工作,但minifilter驱动仅当它必须处理该I/O操作时它才注册。

 

对一个给定的I/O操作来说,只有已经为该I/O操作注册了一个pre-oper callback例程的minifilter驱动才会被Filter管理器调用。Filter管理器也代表minifilter驱动处理某些IRP维护任务,比如复制参数到下一栈位置并传播IRP的PendingReturned标记.

 

在其pre-oper callback例程中,只要是需要对I/O操作进行的处理minifilter驱动都做,而且它会通过在该例程中返回合适的值来指示对这个IRP的什么工作将要被完成。例如,为了不借助完成例程而转寄IRP给下一lower驱动,minifilter驱动就会返回 FLT_PREOP_SUCCESS_NO_CALLBACK;为了借助完成例程来做同样的事情(对此I/O操作的minifilter驱动post-oper callback例程),它就会返回 FLT_PREOP_SUCCESS_WITH_CALLBACK. 

 

在其pre-oper callback例程中,如果需要的话minifilter驱动可以通过调用FltQueueDeferredIoWorkItem将操作queue到一个worker线程。在那之后,minifilter驱动会从它的pre-oper callback 例程中返回FLT_PREOP_PENDING来指示I/O操作正处于pending状态而它要负责该操作的完成或者负责恢复对这个请求的处理。为了恢复处理,minifilter驱动要从工作者线程中调用FltCompletePendedPre-oper. 

 

如果minifilter驱动需要维护它自己的per-instance安全取消要被处理的未决I/O操作的队列,它可以在它的InstanceSetupCallback 例程中调用FltCbdqInitialize 来设立这样一个队列并在需要时在其pre-oper callback 例程中调用FltCbdqInsertIo 来把I/O操作插入到此队列中。

 

当lower过滤驱动(legacy filters和minifilter驱动s)已经结束了完成处理时,filter管理器会调用一个minifilter驱动的 post-oper callback 例程. 

 

在其post-oper callback例程中,minifilter驱动可以调用FltDoCompletionProcessingWhenSafe 来确保在安全的IRQL处理某个I/O操作的完成处理。否则它可以通过调用FltQueueDeferredIoWorkItem 来queue完成处理到一个worker线程。在此之后,minifilter驱动会从其post-oper callback例程中返回FLT_POSTOP_MORE_PROCESSING_REQUIRED来停止Filter管理器对此I/O操作的完成处理。要恢复完成处理,minifilter驱动得从worker线程中调用 FltCompletePendedPost-oper. 

 

Filter管理器为"一般"工作项(关联一个minifilter驱动或minifilter驱动实例而非一个I/O操作的工作项)的队列化提供支持。Minifilter驱动要插入一个工作项到一个系统工作队列中可以通过调用FltQueueGenericWorkItem。此例程和ExQueueWorkItem类似; 例如,工作项(通过调用FltAllocateGenericWorkItem分配)可以被重用.不过,对minifilter驱动来说使用FltQueueGenericWorkItem 会更安全,因为在未决工作项仍处于正被处理状态期间filter管理器不允许minifilter驱动或minifilter驱动实例的卸载。

Filter管理器也为oplock操作提供支持。为了oplock操作,minifilter驱动可以使用像 FltInitializeOplock 和FltOplockFsctrl(与文件系统和legacy过滤驱动所使用的FsRtlInitializeOplock和FsRtlOplockFsctrl例程等价). 

用于处理I/O操作的Filter管理器例程

 

Filter管理器为pre-oper和post-oper callback例程中的pending I/O提供以下支持例程: 

 

FltCompletePendedPost-oper 

FltCompletePendedPre-oper 

FltDoCompletionProcessingWhenSafe 

 

以下例程用于queue pre-oper和post-oper callback例程中的工作项: 

 

FltAllocateDeferredIoWorkItem 

FltAllocateGenericWorkItem 

FltFreeDeferredIoWorkItem 

FltFreeGenericWorkItem 

FltQueueDeferredIoWorkItem 

FltQueueGenericWorkItem 

 

下列例程提供安全取消队列支持: 

 

FltCbdqDisable 

FltCbdqEnable 

FltCbdqInitialize 

FltCbdqInsertIo 

FltCbdqRemoveIo 

FltCbdqRemoveNextIo 

 

下列例程提供oplock支持:

 

FltCheckOplock 

FltCurrentBatchOplock 

FltInitializeOplock 

FltOplockFsctrl 

FltOplockIsFastIoPossible 

FltUninitializeOplock 

 

用于处理I/O操作的Minifilter驱动Callback例程:

 

以下callback例程存储于FLT_OPERATION_REGISTRATION 结构之中,用于minifilter驱动处理的任何一个类型的I/O操作: 

 

Callback例程名

Callback例程类型

Post-oper 

PFLT_POST_OPERATION_CALLBACK 

Pre-oper 

PFLT_PRE_OPERATION_CALLBACK 

 

 

3).修改参数

Minifilter驱动可以修改关联一个I/O操作的某些参数,比如目标实例,目标FileObject和操作指定的参数(包括buffer地址和MDL地址)。minifilter驱动通常在其pre-oper callback中修改这些参数。如果它修改参数,它必须调用FltSetCallbackDataDirty 通知filter管理器:这些参数已经改变了。它也应该在其pre-oper callback的context中记录这些改变,以便它们在其post-oper callback中可用。 

 

当minifilter驱动在它的pre-oper callback中完成某个I/O操作或在它的post-oper callback中令操作失败(比如把STATUS_SUCCESS改为一个错误的状态)时,它可以改变这个操作的I/O状态。在此情形下,不必调用FltSetCallbackDataDirty. 

 

更多关于修改参数的信息可参考Modifying the Parameters for an I/O Operation一文. 

 

minifilter驱动可以通过用自己的buffer替代I/O操作的buffer域来实现"交换buffers". 这样的minifilter驱动负责同步地保存I/O请求的MDL和buffer域. Filter管理器设置FLT_CALLBACK_DATA 中的FLTFL_CALLBACK_DATA_SYSTEM_BUFFER_FLAG来指示一个buffer是否为一个系统buffer;如果是,minifilter驱动必须从非分页池中分配替代buffer并把MDL域设为NULL.否则,buffer可以从分页或非分页池中分配,而minifilter驱动必须总是创建和设置MDL. (在fast I/O操作的情形中,新的buffer可以从分页或非分页池中分配且MDL应该为NULL.) minifilter驱动不能释放它替代的buffer或MDL,也不能释放它已经成功地插入到一个callback数据结构中的一切MDL (filter管理器会代表minifilter驱动释放MDL). 在对一个MDL或buffer做出改变之后,minifilter驱动必须调用FltSetCallbackDataDirty. 

 

minifilter驱动必须为它要在其中交换buffer的操作注册一个post-oper callback.在这个callback例程中,minifilter驱动必须释放它分配的一切buffer.filter管理器会释放MDL除非minifilter驱动调用FltRetainSwappedBufferMdlAddress;在此情形下, minifilter驱动负责释放MDL.minifilter驱动要获得在其pre-oper callback中设置的buffer的MDL可以调用 FltGetSwappedBufferMdlAddress. 

 

如果minifilter驱动在某个操作中已经交换了buffer,而在此操作期间它被卸载,则该操作不能被"耗尽";取而代之的是,此操作会被取消而filter管理器在卸载这个minifilter驱动之前要等待该操作的完成. 

 

SwapBuffers例子可以作为一个交换buffer的minifilter驱动的例子。

 

用于修改参数的Filter管理器例程:

 

Filter管理器为在pre-oper和post-oper callback例程中修改I/O操作参数提供下列支持例程: 

 

FltClearCallbackDataDirty 

FltIsCallbackDataDirty 

FltSetCallbackDataDirty 

 

下列例程为交换buffer提供支持:

 

FltGetSwappedBufferMdlAddress 

FltRetainSwappedBufferMdlAddress 

4).访问User Buffers 

指定给一个给定I/O操作的所有参数(包括buffer和MDL)都被定义在一个FLT_PARAMETERS 联合体中.此联合体包含在一个FLT_IO_PARAMETER_BLOCK 结构中,此结构通过表示I/O操作的FLT_CALLBACK_DATA 结构的Iobp 成员来访问。filter管理器和minifilter驱动都使用FLT_CALLBACK_DATA 结构来初始化和处理I/O操作。 

 

FLT_PARAMETERS联合体也包含给基于IRP的操作的参数定义,这些参数由该操作使用的buffering方式(buffered,direct I/O或者neither)指定. 它也包含非基于IRP的操作的参数定义(fast I/O和FsFilter callback例程). 

 

minifilter驱动可以调用FltDecodeParameters 来获得MDL地址的指针,buffer指针,buffer长度和一个I/O操作期望的访问参数。这使得minifilter驱动拥有了一个切换声明来在(跨多个I/O操作访问这些参数的)帮助例程中找到这些参数的位置。 

 

当处理一个调用了user buffer的I/O操作时,如果MDL可用则minifilter驱动应总是使用MDL。若如此,minifilter驱动应调用MmGetSystemAddressForMdlSafe 来获得MDL的系统地址并用这个系统地址来访问user buffer. 

 

若只有buffer地址可用,则minifilter驱动应总是在try/except块中封装对buffer的一切访问意图。如果minifilter驱动需要在一个不同步的post-oper callback例程中访问buffer,或者如果I/O操作被发给一个worker线程,则minifilter驱动也应该通过调用FltLockUserBuffer锁住user buffer.此函数基于I/O操作的类型决定要请求锁住的buffer所采用的访问方式并创建一个指向已锁页的MDL。

 

用于访问User Buffers 的Filter管理器例程:

 

filter管理器为在pre-oper和post-oper callback例程中访问user buffer提供了以下支持例程: 

 

FltDecodeParameters 

FltLockUserBuffer 

原创粉丝点击