今天看到了WSK,又有事情做了,一直是这样,肯定不行,我要想办法,当然,人千万不能漂起来,因为,自己不说很成熟,但是已经工作了这么多年。经过的事情,见过的人已经很多了。对于,自己,我觉得,应该有着相当的自信,因为,这么多年来,我一直在严格要求自己,从来没有放松过对自己的要求。现在的这个世界,已经,变成了一个爆发的世界,各种各样的人,都可以表演,只要敢做,就有机会,虽然难,但是比之前的环境要好很多。我觉得自己应该抓住这样的机会,好好利用,不是为了找工作而找工作,应该抱着找事业的心来找工作。
Managing Contexts in a Minifilter Driver
上下文空间是微小过滤驱动定义的一个结构,它可以和过滤驱动管理的对象相关联。微小过滤驱动可以为如下的对象创建和设置上下文。
Files (Windows Vista and later only.)
Instances
Volumes
Streams
Stream handles (file objects)
Transactions (Windows Vista and later only.)
除了卷的上下文,空间必须在非分页内存上分配以外,其它的上下文既可以在分页内存上分页也可以在非分页内存上分配。
Registering Context Types
当微小过滤驱动在DriverEntry中调用FltRegisterFilter的时候,它必须为它要使用的每一个上下文注册一中类型。
为了去注册上下文类型,微小过滤驱动可以创建一个可变长度类型为FLT_CONTEXT_REGISTERATION结构的数组,将其指针装入到FLT_REGISTERATION结构的成员ContextRegistration中。在数组中元素的顺序不用关心,但是最后一个原书必须是{FLT_CONTEXT_END}.
对于每一个微小过滤驱动使用的上下文类型,它必须在FLT_CONTEXT_REGISTRATION结构至少定义一种上下文类型。每一个FLT_CONTEXT_REGISTRATION结构定义了上下文的大小,类型,其它的一些信息。
当微小过滤驱动调用FltAllocateContext创建一个新的上下文的时候,过滤管理器使用FltAllocateContext例程的Size参数,和FLT_CONTEXT_REGISTRATION结构中的成员Size和Flags,去选择被使用的上下文定义。
对于固定大小的上下文,FLT_CONTEXT_REGISTRATION结构成员Size域指定了由微小过滤驱动定义的上下文的以字节计数的大小。上下文最大的空间大小是64KB。0是一个有效的大小值。过滤管理器使用lookaside列表执行固定大小的上下文。过滤管理器为每一个size值创建两个lookaside,一个是分页的一个是非分页的。
对于可变大小的上下文,Size成员必须设置为FLT_VARIABLE_SIZED_CONTEXT.过滤管理器直接从分页或非分页内存分页可变长度大小的上下文。
在FLT_CONTEXT_REGISTRATION结构体的Flags成员FLTFL_CONTEXT_REGISTRATION_NO_EXACT_SIZE_MATCH标志可以被指定。如果微小过滤驱动使用固定大小的上下本而且这个标志被指定,过滤管理器会从lookaside列表中分配比请求大于或等于的空间给上下文。否则的话,上下文空间必须等于请求的大小。
对于给定的上下文类型,微小过滤驱动可以提供最大到三种固定大小的上下文结构的定义。每一种都是可变的大小,可变的size的定义。
微小过滤驱动也可以选择去提供一个上下文清除例程,在上下文被释放前被调用。可以查看PFLT_CONTEXT_CLEANUP_CALLBACK.
微小过滤驱动可以为分配和释放上下文操作定义相应的回调例程,而替代上面的过滤管理器执行的操作。但是,这样使用非常少。详细可了解:PFLT_CONTEXT_ALLOCATE_CALLBACK and PFLT_CONTEXT_FREE_CALLBACK.
下面例子的实例演示了,FLT_CONTEXT_REGISTRATION结构的数组,用于注册实例,文件,流,文件对象的上下文。
const FLT_CONTEXT_REGISTRATION contextRegistration[] =
{
{ FLT_INSTANCE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_INSTANCE_CONTEXT_SIZE, //Size
CTX_INSTANCE_CONTEXT_TAG //PoolTag
},
{ FLT_FILE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_FILE_CONTEXT_SIZE, //Size
CTX_FILE_CONTEXT_TAG //PoolTag
},
{ FLT_STREAM_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_STREAM_CONTEXT_SIZE, //Size
CTX_STREAM_CONTEXT_TAG //PoolTag
},
{ FLT_STREAMHANDLE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_STREAMHANDLE_CONTEXT_SIZE, //Size
CTX_STREAMHANDLE_CONTEXT_TAG //PoolTag
},
{ FLT_CONTEXT_END }
};
Creating Contexts
一旦,微小过滤驱动注册了一个上下文的类型,它就通过调用FltAllocateContext创建上下文。这个例程根据Registering Context Types中的描述,选择相应的上下文定义。
下面这个例子,演示了在实例安装的例程中调用FltAllocateContext来创建一个实例上下文:
status = FltAllocateContext(
FltObjects->Filter, //Filter
FLT_INSTANCE_CONTEXT, //ContextType
CTX_INSTANCE_CONTEXT_SIZE, //ContextSize
NonPagedPool, //PoolType
&instanceContext); //ReturnedContext
如下的代码演示了,实例上下文的注册:
{ FLT_INSTANCE_CONTEXT, //ContextType
0, //Flags
CtxContextCleanup, //ContextCleanupCallback
CTX_INSTANCE_CONTEXT_SIZE, //Size
CTX_INSTANCE_CONTEXT_TAG }, //PoolTag
这个是固定大小上下文的定制一,因为Size成员是一个常量(如果Size成员FLT_VARIABLE_SIZED_CONTEXT,就是一个变长上下文定义)。注意Flags成员中没有设置FLTFL_CONTEXT_REGISTRATION_NO_EXACT_SIZE_MATCH 标志。在这种情况下FltAllocateContext例程中的Size参数更上下文定义中的Size成员、相等,FltAllocateContext从相应的非分页的lookaside中分配实例的上下文的空间。如果值不相等,FltAllocateContext失败,返回 STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND。
FltAllocateContext初始化新创建的上下文的引用计数为1.当上下文不再需要的时候,微小过滤驱动必须释放这个引用。所以FltAllocateContext必须和FltReleaseContext
成对调用。
Setting Contexts
创建一个新的上下文以后,微小过滤驱动可以通过调用FltSetXxxContext函数将其附加在对象上。
如果FltSetXxxContext例程的参数Operation被设置为FLT_SET_CONTEXT_KEEP_IF_EXISTS,在微小过滤驱动还没有为其对象设置上下文的情况下,FltSetXxxContext例程才将新创建的上下文附加到对象上。如果微小过滤驱动已经为对象设置了上下文,FltSetXxxContext返回一个错误NTSTATUS值STATUS_FLT_CONTEXT_ALREADY_DEFINED,
不会替换存在的上下文。如果FltSetXxxContext例程的OldContext参数不为NULL,它接收一个指向存在的上下文的指针。当这个指针不再需要的时候,微小过滤驱动必须调用FltReleaseContext将其释放。
如果Operation参数被设置为FLT_SET_CONTEXT_REPLACE_IF_EXISTS,FltSetXxxContext例程一直将新的上下文附加在对象上。如果微小过滤驱动已经为对象设置了上下文,FltSetXxxContext删除存在的上下文,设置新的上下文,并增加新的上下文的引用计数。如果OldContext参数不为NULL,它接收一个指向删除上下文的指针。当这个指针不再需要,微小过滤驱动必须通过调用FltReleaseContext将其释放。
如下的例子,演示了,在CtxInstanceSetup实例中创建并设置一个实例上下文。
status = FltAllocateContext(
FltObjects->Filter, //Filter
FLT_INSTANCE_CONTEXT, //ContextType
CTX_INSTANCE_CONTEXT_SIZE, //ContextSize
NonPagedPool, //PoolType
&instanceContext); //ReturnedContext
...
status = FltSetInstanceContext(
FltObjects->Instance, //Instance
FLT_SET_CONTEXT_KEEP_IF_EXISTS, //Operation
instanceContext, //NewContext
NULL); //OldContext
if (instanceContext != NULL) {
FltReleaseContext(instanceContext);
}
return status;
注意:调用FltSetInstanceContext后,掉用FltReleaseContext去释放被FltAllocateContext增加的引用计数。
Getting Contexts
一旦,微小过滤驱动为对象设置了一个上下文,就可以通过调用FltGetXxxContext得到上下文的内容。
在如下的代码示例中,微小过滤驱动调用FltGetVolumeContext得到卷的上下文。
status = FltGetVolumeContext(
FltObjects->Filter, //Filter
FltObjects->Volume, //Volume
&volCtx); //Context
...
if (volCtx != NULL) {
FltReleaseContext(volCtx);
}
如果调用FltGetVolumeContext是成功的,Context参数将接收到一个调用者卷的上下文的地址。FltGetVolumeContext增加了上下文指针的引用计数。当指针不再需要的时候,微小过滤驱动必须通过调用FltReleaseContext将其释放。
Referencing Contexts
过滤管理器使用引用计数来管理微小过滤驱动的上下文的生命周期。引用计数是一个数字指明上下文的状态。当上下文创建的时候,其引用计数被初始化为1,当上下文被系统的部件引用,上下文的引用计数被加1.当上下文不再需要,它的引用计数被递减,一个正个引用计数意味着上下文可用。当引用计数变成0,上下文没有在用。
过滤管理器会删除它。
当对象被卸载的时候上下文的初始化引用被释放。然而,如果微小过滤驱动必须从对象中删除上下文,微小过滤驱动必须释放上下文的引用。为了安全的释放上下文的引用,微小过滤驱动必须调用FltDeleteContext.
微小过滤驱动可以调用FltReferenceContext增加对上下文的引用计数,通过FltReleaseContext删除引用计数。
Releasing Contexts
微小过滤驱动通过调用FltReleaseContext释放上下文的引用计数。每一次成功调用如下的例程都必须调用一次FltReleaseContext.
FltAllocateContext
FltGetInstanceContext
FltGetFileContext
FltGetStreamContext
FltGetStreamHandleContext
FltGetTransactionContext
FltGetVolumeContext
FltReferenceContext
注意:被FltSetXxxContext返回的OldContext的指针和被FltDeleteContext返回的Context指针当不再需要的时候,都必须删除。
下面的代码演示了,在CtxInstanceSetup例程中创建并设置实例上下文,然后调用FltReleaseContext释放其引用计数。
status = FltAllocateContext(
FltObjects->Filter, //Filter
FLT_INSTANCE_CONTEXT, //ContextType
CTX_INSTANCE_CONTEXT_SIZE, //ContextSize
NonPagedPool, //PoolType
&instanceContext); //ReturnedContext
...
status = FltSetInstanceContext(
FltObjects->Instance, //Instance
FLT_SET_CONTEXT_KEEP_IF_EXISTS, //Operation
instanceContext, //NewContext
NULL); //OldContext
if (instanceContext != NULL) {
FltReleaseContext(instanceContext);
}
return status;
注意:不管调用FltSetInstanceContext是否成功,FltReleaseContext都必须调用。在两种情况下,调用者都必须调用FltReleaseContext去使用由调用FltAllocateContext增加的引用计数。
如果上下文被成功的对实例设置。FltSetInstanceContext增加实例上下文的引用计数。通过调用FltAllocateContext的引用计数不再需要,调用FltReleaseContext释放它。
如果调用FltSetInstanceContext失败,实例上下文的引用计数仅仅是1,仅仅是通过FltAllocateContext增加的,当FltReleaseContext返回,实例上下文的引用计数变层0,
通过过滤管理器将其释放。
Deleting Contexts
每一个通过成功调用FltSetXxxContext设置的上下文最后必须被删除掉,尽管,过滤管理器在器对象被删除的时候会自动删除它的上下文,当过滤驱动的实例从卷上被卸载,当驱动卸载的时候。很少,由驱动明确的去删除上下文的。
微小过滤驱动可以通过FltDeleteXxxContext去删除上下文。
上下文可以被删除的条件是它已经被设置在对象上,如果一个上下文还没被设置到对象上,它就不能被删除,或者通过FltSetXxxContext去替换。
在调用FltDeleteXxxContext的时候,如果原始的上下文不为NULL,它将返回在OldContext参数中。如果OldContext为NULL,过滤管理器将递减上下文上的引用计数,然后被释放,除非微小过滤驱动有对其有一个引用。
如下的代码,演示如何删除流的上下文。
status = FltDeleteStreamContext(
FltObjects->Instance, //Instance
FltObjects->FileObject, //FileObject
&oldContext); //OldContext
...
if (oldContext != NULL) {
FltReleaseContext(oldContext);
}
在这个例子中,FltDeleteStreamContext从流上删除流的上下文,但是它并没有递减其上下文的引用计数,因为OldContext参数不为NULL.FltDeleteStreamContext返回了删除的上下文的地址在OldContext参数中。执行一些需要的操作以后,调用者调用FltReleaseContext来释放删除的上下文。
Freeing Contexts
上下文在其被删除和其所有的引用计数都被释放的时候,上下文就被释放。
不过有一种情况例外,如果上下文已经被创建,但是还没有通过调用FltSetXxxContext将其设置,它就不需要被删除。当其引用计数到达0之后它就被释放。
当微小过滤驱动注册它的上下文类型,每一个上下文定义,可以有选择的保护一个上下文清楚回调函数,这个回调函数在上下文被释放时,这个例程被调用。
File System Support for Contexts
为了去支持文件上下文,流上下文,文件对象上下文,文件系统必须使用FSRTL_ADVANCED_FCB_HEADER结构。所有的微软Windows文件系统都使用这个结构,所有
的第三方文件系统的开发者也建议使用这个结构。可以看FsRtlSetupAdvancedHeader和FSRTL_ADVANCED_FCB_HEADER.
NTFS和FAT文件系统在预前创建或延后关闭或IRP_MJ_NETWORK_QUERY_OPEN的操作中在分页文件上不支持文件,流或文件对象的上下文.
微小过滤驱动可以通过调用FltSupportStreamContext和FltSupportsStreamHandleContexts各自去探测是否文件系统支持流上下文和文件对象上下文。
文件上下文应用于WINDOWS VISTA以后。
对于那些在一个文件上只支持一个数据流的文件系统(FAT),文件上下文等价于流上下文。这些文件系统,通常支持流上下文但是不支持文件上下文。这种情况下,过滤管理器提供其支持,通过文件系统存在的流上下文的支持。对于附加在这些文件系统上面的微小过滤驱动的实例来说,FltSupportsFileContexts
返回FALSE,FltSupportsFileContextsEx返回TRUE(当一个有效的非NULL值传递给Instance参数)。
为了去支持文件上下文,文件系统必须:
内置一个类型为PVOID的FileContextSupportPointer成员在其文件上下文结构中,通常是文件上下文块(FCB).文件系统必须初始化这个成员为NULL.
使用FsRtlSetupAdvancedHeaderEx(替换FsRtlSetupAdvancedHeader)去初始化流的上下文结构,传递一个有效的指针给 FileContextSupportPointer 成员到FileContextSupportPointer 参数中。详细可以看FsRtlSetupAdvancedHeaderEx and FSRTL_ADVANCED_FCB_HEADER。
当文件系统为文件删除其文件上下文结构的时候,调用FsRtlTeardownPerFileContexts去释放所有的原始过滤驱动和微小过滤驱动已经将其和文件相关联的上下文结构。
Best Practices
如果微小过滤驱动对于每一个卷仅仅只有一个微小过滤驱动的实例,使用实例上下文比卷上下文,可以得到更好的系统表现。
微小过滤驱动也可以通过将其实例上下文的指针装入到流或流句柄的航线中,提高系统的表现。