FltDoCompletionProcessingWhenSafe vs FltQueueDeferredIoWorkItem

I’ve recently taken over the development of an HSM/minifilter project
and I’m a bit new to doing Windows driver development. At this point,
I’m about to jump into the first really technical task I’ve tackled on
the project, and I had a couple questions I was hoping somebody could
please answer.

Currently, the driver retrieves the file from long term storage on
Create requests, but for a couple of reasons, we’ve decided to move the
retrieval so it happens on reads instead. Obviously, this complicates
things, as we’re no longer guaranteed to be running at PASSIVE_LEVEL.

First: We currently return from either
FLT_POSTOP_MORE_PROCESSING_REQUIRED or FLT_POSTOP_FINISHED_PROCESSING
depending upon whether we can handle the request. However, some of the
logic depends upon being able to call functions that need to occur at
<=APC_LEVEL. Would a correct solution for the new version be to do as
much of the checking as possible at arbitrary IRQL (potentially
DPC_LEVEL, if I understand the docs and past NG discussions correctly)
queue the remaining checking and return
FLT_POSTOP_MORE_PROCESSING_REQUIRED? This leaves the other checking to
happen at a safe IRQL later, and if we can’t do the processing then
because of some error, we complete the request with a failure code of
some sort in the FLT_CALLBACK_DATA struct.

Second: The filter driver’s role in the retrieval process is *very*
minimal: all the heavy lifting is done in a userland service that the
filter communicates with by Flt(Send/Receive)Message. If it turns out
that we don’t need to do anything that requires PASSIVE_LEVEL, it looks
like we’d be able to use either FltDoCompletionProcessingWhenSafe or
FltQueueDeferredIoWorkItem. Is one preferable over the other for
reasons I haven’t run across yet? In this thread
(http://www.osronline.com/showThread.cfm?link=68216) it is suggested
that they’re interchangeable if you don’t need PASSIVE_LEVEL, so I’m
deferring to the list to ask if there are any caveats about one or the
other I should know about that I haven’t uncovered on MSDN or the DDK
docs. Or should I just queue a work item in case we need to add
functionality down the road that requires being at PASSIVE_LEVEL?

Third: Can a write occur on a file without a preceding read? This
feels like a really dumb question, but one I feel I should ask before I
make any assumptions. On one hand, the answer would seem to be no, On
the other hand, it seems possible that when you open for append, nothing
would actually have to read the file since the FS has to know the size
of the file anyway. The trivial case of a new file doesn’t apply here,
since it couldn’t be in long term storage if it never existed locally.

Thanks,

~Eric Diven

>>Second: The filter driver’s role in the retrieval process is *very*
minimal: all the heavy lifting is done in a userland service that the
filter communicates with by Flt(Send/Receive)Message. If it turns out
that we don’t need to do anything that requires PASSIVE_LEVEL, it looks
like we’d be able to use either FltDoCompletionProcessingWhenSafe or
FltQueueDeferredIoWorkItem. Is one preferable over the other for
reasons I haven’t run across yet? In this thread
(http://www.osronline.com/showThread.cfm?link=68216) it is suggested
that they’re interchangeable if you don’t need PASSIVE_LEVEL, so I’m
deferring to the list to ask if there are any caveats about one or the
other I should know about that I haven’t uncovered on MSDN or the DDK
docs. Or should I just queue a work item in case we need to add
functionality down the road that requires being at PASSIVE_LEVEL?<<

FltDoCompletionProcessingWhenSafe checks whether the IRQL<=APC_LEVEL and if
it is, it immediately calls the function specified as SafePostCallback. If
the IRQL is not safe ( IRQL>APC_LEVEL ), it queues the callbackdata for
later processing ( later being the time when the IRQL <=APC_LEVEL ) and then
calls that function.

On the other hand, FltQueueDeferredIoWorkItem queues up the callbackdata
even if the IRQL<=APC_LEVEL.

An important difference between FltQueueDeferredIoWorkItem &
FltDoCompletionProcessingWhenSafe is that the function specified in
FltQueueDeferredIoWorkItem will be called ONLY AT PASSIVE_LEVEL. However,
the function specified in FltDoCompletionProcessingWhenSafe can be called
either at PASSIVE_LEVEL or APC_LEVEL.

I suggest that if by any chance your filter has the rarest possibility of
calling functions for logging errors, etc., use FltQueueDeferredIoWorkItem.
Its guaranteed that your worker thread function will be called at
PASSIVE_LEVEL, and in my opinion it is the SAFEST IRQL and using the safest
irql is anytime better than safe irql.

>Third: Can a write occur on a file without a preceding read? This
feels like a really dumb question, but one I feel I should ask before I
make any assumptions. On one hand, the answer would seem to be no, On
the other hand, it seems possible that when you open for append, nothing
would actually have to read the file since the FS has to know the size
of the file anyway. The trivial case of a new file doesn’t apply here,
since it couldn’t be in long term storage if it never existed locally.<<

Depending upon whether the file has been opened in cached mode or non cached
mode, it may happen or not.
A write operation can directly be performed on a non cached file. However,
in cached file it is not possible. Even though you will not read the file
explicitly, the VMM will read in the pages from the file.

Cheers!

Ayush Gupta
K7 Computing Private Limited.
www.k7computing.com

Thank you Ayush,

I’ve gone ahead and done the basic reimplementation using FltQueueDeferredIoWorkItem, it seems like the right way to go for now.