FltDoCompletionProcessingWhenSafe

Hi,

I would like to use FltDoCompletionProcessingWhenSafe when processing cached write completions that may come in at IRQL > PASSIVE_LEVEL.

The swap buffers example does this.

However, MSDN has the following tidbit in the documentation for that routine:

"Caution To avoid deadlocks, FltDoCompletionProcessingWhenSafe cannot be called for I/O operations that can be directly completed by a driver in the storage stack, such as the following:

IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS"

Who is correct?

Thanks,
Matt

Hi Matt,

Well, the documentation is too restrictive. The deadlocks it is referring to can happen if the post-operation callback also issues IO. In that case the second IO could be blocked on the lock(s) protecting the IO stack that are already hold on the original IO.

It very much depends on what your post-operation callback does.

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.

Well, I was going to extend the size of the underlying file in certain circumstances using IRP_MJ_SET_INFORMATION (to make sure that subsequent paging IO that I may offset has room to complete), however based on your explanation I think this is probably a no no. Right? Or by IO do you mean just further reads or writes.

If this is not doable in the completion routine I can move the processing to the dispatch routine since it’s not critical if the size of the underlying file is too large if the write happens to fail for some reason.

Thoughts?

Thanks,
Matt

Hmm… sorry, I mistyped something. When I said " lock(s) protecting the IO stack" I was referring to the storage stack. So, by IO I mean any IO that might end up waiting on the storage stack (not only reads and writes). I guess that extending the size might end up waiting on the IO stack.

Moving it to the pre callback should work. Also, queuing a work item from the post callback should work as well.

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.

FltQueueDeferredIoWorkItem has the same disclaimer as FltDoCompletionProcessingWhenSafe in MSDN. You are saying that if I queue it I won’t have a problem?

I decided to queue it anyway since I need to call FltSetInformationFile at PASSIVE_LEVEL (though honestly I don’t understand some of these requirements since I can do FltAllocateCallbackData and FltPerformSynchronousIo at APC_LEVEL - it seems that you should be able to call FltSetInformationFile and other Flt IO APIs at APC_LEVEL in certain circumstances).

You should be safe if you queue and don’t wait. The “comments” section in MSDN has an example for the post-operation path where they pend the IO, but you don’t want to do that (it’s pretty much the same thing as the other deadlock). Just queue it and don’t wait (assuming, of course, that the architecture of your minifilter allows it).

I agree with the requirements not being clearly explained. We want to improve the documentation to explain how we arrived at the levels requirements, but that is a long way from now.

You could roll your own CALLBACK_DATA and FltPerformSynchronousIo if you know the rules for the particular information class you need.

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.

I’m lost now. How do you queue something and not wait (pend the IO)? I thought that when you queue the IO to a worker thread you need you need to pend the original request or the IO/filter manager will cleanup the underlying callback data, IRP, etc. No?

When you see an IO in your minifilter and you need to perform a certain operation in response to it and you can’t or won’t do that operation in the original context, you need to schedule a work item. Then you have two options:

  1. to block the IO until the operation is done (depends on your architecture…). Which means there is one more decision to make:
    1.1. return pending
    1.2. wait for the work-item to be done (synchronize it)
  2. to let the IO continue (let’s say your minifilter counts the number of writes/sec in the system; if it misses one it’s ok… ) in which case you return FLT_PREOP_SUCCESS_XXX_CALLBACK and hope that the work item gets scheduled ever… Of course, you need to properly reference everything you need to pass in the context to your work item, since, as you pointed out, they might go away…

This is overly simplifying things, but…

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.