Share via


File System Minifilter Drivers (Part 2)

In my last entry I covered some basic information about file system minifilter drivers.  This entry I want to talk about more about them, specifically their context support.  I don’t think I will make this as long as I previously planned on because I think I want to separate my discussion of callback rules and top tips into a separate entry.

A driver’s support for contexts begins with the call to FltRegisterFilter.  The FLT_REGISTRATION typed variable passed into that function includes a pointer to a FLT_CONTEXT_REGISTRATION structure.  This structure is pretty simple:

typedef struct _FLT_CONTEXT_REGISTRATION {

    FLT_CONTEXT_TYPE ContextType;

    FLT_CONTEXT_REGISTRATION_FLAGS Flags;

    PFLT_CONTEXT_CLEANUP_CALLBACK ContextCleanupCallback;

    SIZE_T Size;

    ULONG PoolTag;

    PFLT_CONTEXT_ALLOCATE_CALLBACK ContextAllocateCallback;

    PFLT_CONTEXT_FREE_CALLBACK ContextFreeCallback;

    PVOID Reserved1;

} FLT_CONTEXT_REGISTRATION, *PFLT_CONTEXT_REGISTRATION;

Most of this is explained well in MSDN so I won’t go into what each field is, but it is important to remember that if you register multiple context definitions (for the same context type) with varying sizes you need to specify FLTFL_CONTEXT_REGISTRATION_NO_EXACT_SIZE_MATCH so that the Filter Manager does not fail the allocations of your contexts.

After that it is easy to allocate a context using FltAllocateContext.  Currently the context types supported are: FLT_INSTANCE_CONTEXT, FLT_STREAM_CONTEXT, FLT_STREAMHANDLE_CONTEXT, and FLT_VOLUME_CONTEXT (file contexts are not yet supported).  Finally, after being allocated, a context can be set by calling the respective FltSetxxxContext routine.  The point of these contexts is to have an easy mechanism for attaching information to an instance, a stream, a stream handle, or a volume that is easily retrievable, reference counted, and garbage collected by the Filter Manager.

When I was using stream handle contexts in my first minifilter, the main problem I had was with reference counting.  At a basic level it is pretty simple.  The reference count on a context is increased whenever you call an FltGetxxxContext routine and you’ll need to call FltReleaseContext when you are done working with the context you retrieved.  You can also manually reference a context with FltReferenceContext.  The problem I had was in understanding what happens when you allocate and set a context.

The simple answer is that both increment the reference count.  So, in the MSDN entry for FltSetxxxContext it says you need to call FltReleaseContext for a successful or a failed FltSetxxxContext call.  The problem is that there is actually a bit of a difference in the failure and successful case.  If the set context fails you actually need to call FltReleaseContext twice to remove the reference from the allocation and the failed set context call to get the context to be garbage collected.  In the successful case you call FltReleaseContext to get rid of the reference count from the allocation and you are left with a reference count of one on the context.

The other thing to watch out for is close operations.  For instance, the reference count on my stream handle contexts was automatically decremented on a successful close of the file (in between the PreClose and PostClose callbacks).  If you understand what causes reference count events on your contexts and keep close track of them the Filter Manager’s support for reference counting and context cleanup callbacks are extremely helpful.

That is about all I have to say about context support in the Filter Manager.  The Filter Manager’s support for contexts makes them extremely powerful and easy to use, but also very generic.  They should be a good fit for any information you need to attach to a specific instance, stream, stream handle, or volume.

In my next post I will discuss some general rules of callbacks (specifically IRQL levels and the issues around handling that) and some of my general tips for working with the Filter Manager.