process context and IRQL in minifilter callbacks

Hi,

Can somebody confirm that a POST-Create callback in a minifilter is always called at PASSIVE_LEVEL and *in the context of the original calling thread*?

(AFAIK, this is always guaranteed for a PRE-Create callback, but I’m not 100% sure about POST-Create).

thank you very much,

Sandor

Yes. This is guaranteed for PostCreate.

Taken from docs for “PFLT_POST_OPERATION_CALLBACK”:

"Post-create callback routines are guaranteed to be called at IRQL
PASSIVE_LEVEL, in the context of the thread that originated the
IRP_MJ_CREATE operation. "

wrote news:xxxxx@ntfsd…
> Hi,
>
> Can somebody confirm that a POST-Create callback in a minifilter is always
> called at PASSIVE_LEVEL and in the context of the original calling
> thread
?
>
> (AFAIK, this is always guaranteed for a PRE-Create callback, but I’m not
> 100% sure about POST-Create).
>
> thank you very much,
>
> Sandor
>

Frank wrote:

Yes. This is guaranteed for PostCreate.

Taken from docs for “PFLT_POST_OPERATION_CALLBACK”:

"Post-create callback routines are guaranteed to be called at IRQL
PASSIVE_LEVEL, in the context of the thread that originated the
IRP_MJ_CREATE operation. "

Thank you very-very much :slight_smile:

(I just don’t realize how could I miss that phrase… I have checked the
docs)

Sandor

wrote news:xxxxx@ntfsd…
>> Hi,
>>
>> Can somebody confirm that a POST-Create callback in a minifilter is
>> always called at PASSIVE_LEVEL and in the context of the original
>> calling thread
?
>>
>> (AFAIK, this is always guaranteed for a PRE-Create callback, but I’m
>> not 100% sure about POST-Create).
>>
>> thank you very much,
>>
>> Sandor
>>
>

Vista & Longhorn support asynchronous creates, so it might be called in worker thread context. I am not an expert in mini-filters but I suppose post-operation is called from completion routine.

Anyway IO manager and system is ready for cases when synchronous request is handled asynchronously. It waits for notification event for synchronous IRPs in case STATUS_PENDING is returned, so my opinion is that all filters on the stack must be also ready for it. You can be sure with passive level but not with thread context.
-bg

Thank you very much,

xxxxx@xythos.com wrote:

Vista & Longhorn support asynchronous creates, so it might be called in worker thread context. I am not an expert in mini-filters but I suppose post-operation is called from completion routine.

Anyway IO manager and system is ready for cases when synchronous request is handled asynchronously. It waits for notification event for synchronous IRPs in case STATUS_PENDING is returned, so my opinion is that all filters on the stack must be also ready for it. You can be sure with passive level but not with thread context.
-bg

Now, as I understand, this would be in contradiction with the docs,
which state “Post-create callback routines are guaranteed to be called
at IRQL PASSIVE_LEVEL, in the context of the thread that originated the
IRP_MJ_CREATE operation.” (credits to Frank ;-). However, your logic is
plausible. If a create can be handled asynchronously, so, for example an
upper level filter completes the request with STATUS_PENDING, then
issues down the create request from a worker thread, then, I shall
receive my POST-Create (and PRE-Create also) in the context of that
worker thread. Can this really be the case? If yes, then how frequent
would be in real world? Can smb. confirm it?

thank you very much,

Sandor

> Vista & Longhorn support asynchronous creates, so it might be called in
worker

thread context

…or probably FltMgr will disable this facility and always run creates
synchronously.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

>I shall receive my POST-Create (and PRE-Create also) in the context of that >worker thread.
Only post-create can be called in another thread context as a part of completion. Pre-create must be called in non-arbitrary context in other case it is misbehavior of the filter above you.

This feature (asynchronous creates) was introduced especially to allow canceling of redirectors so system is more responsive when you e.g. terminate an application which hung because of unspecified network problems.

It looks like some update introduced this feature even on XP, because I saw here in this discussion at least two cases when minifilter programmer complained to deadlock in IopParseDevice in KeWaitForSingleObject() right after IopCallDriver() which indicates that even ntfsd returned STATUS_PENDING from its create dispatch routine. But it’s just rumors. I didn’t see such crash dump personally.

If yes, then how frequent would be in real world?
Even if it were once per several weeks for only one customer it would bring many problems in reproducibility if you make wrong design decision now.

-bg

>…or probably FltMgr will disable this facility and always run creates

synchronously.

Maybe someone from MSFT can make things clear.
-bg

> Maybe someone from MSFT can make things clear.

I’m not so great in this particular topic, but IIRC async creates in Win6 are
only at FSD level and not at app level.

I.e. there is no CreateFile-style API to open the file in overlapped mode, but
the driver itself is allowed to pend MJ_CREATE (in some queue, for instance, in
redirector, waiting for transaction response to arrive) and return
STATUS_PENDING to the IO manager.

This does not provide overlapped create semantics to apps, but this provide for
cancellable creates - and cancellable creates is what is the whole feature is
about in Win6.

Even if FltMgr will synchronize the create path by waiting for IRP completion
by the lower FSD (which can be necessary to provide the IRQL/thread context
guarantees in PostCreate) - then the IRP will still be cancellable inside the
lower FSD, so, the feature is not lost.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Maxim, good point! I didn’t get so far in my thoughts. I knew that this feature is invisible to apps. It is only between MUP and redirectors. I didn’t realize that even if any filter above FSD makes this request synchronous it doesn’t prevent caller from ability to cancel it.
-bg

Thank you Maxim :wink:

I also found http://www.osronline.com/showThread.cfm?link=109469, it is good to be read regarding the subject. An important idea is, that Yes, in a minifilter I can get the PRE-Create and POST-Create in a different thread, but, if every other upper minifilter does it’s job correctly, then the security context etc. must be the very same as it would be if the call would have been processes synchronously.

One more question remains: in asynchronous cases what PID is given back by FltGetRequestorProcessId? It is guaranteed to be the the PID of the original thread (I presume yes, but it would be nice to get a confirmation)?

have a nice day,

Sandor

I’d be surprised if that was the case, as there’s fltmgr filters in-box. It would be pretty silly to support a new feature in the I/O system like that and then disable it’s use forevermore.

C:\Windows\system32>fltmc

Filter Name Num Instances Altitude Frame


luafv 1 135000 0
FileInfo 8 45000 0

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Thursday, July 31, 2008 6:52 AM
To: Windows File Systems Devs Interest List
Subject: Re:[ntfsd] process context and IRQL in minifilter callbacks

Vista & Longhorn support asynchronous creates, so it might be called in
worker
thread context

…or probably FltMgr will disable this facility and always run creates
synchronously.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Hello all,

Synchronizing to the original thread does not disable cancellable creates if the proper wait functions are used (see the documentation for FsRtlCancellableWaitForSingleObject for example).

Filter manager guarantees that the in the case of creates (as well as any synchronized operation) the post callback will be called in the same context as the pre callback. If another filter (it would have to be a legacy filter, I don’t see how a minifilter could do this) changes the thread context above filter manager then that’s the context both the pre and post callbacks will be called (if the operation is synchronized). In the thread mentioned above (http://www.osronline.com/showThread.cfm?link=109469), Tony’s filter could change the context above a certain filter manager frame (for the frames above Tony’s filter, if any, it wouldn’t matter) but then both the pre and the post callback for all the minifilters* would still be called in the same context (which is Tony’s filter new context).

So, Sandor, when you say " Yes, in a minifilter I can get the PRE-Create and POST-Create in a different thread " there are two possible interpretations:

  1. the contexts are different for pre and post (which cannot happen)
  2. the contexts are the same for pre and post, but it’s not the same thread that issued the original create (which can happen).

The same two interpretations apply to the original question:
" Can somebody confirm that a POST-Create callback in a minifilter is always called at PASSIVE_LEVEL and *in the context of the original calling thread*?"

  1. If by " context of the original calling thread " you mean the thread where the PRE-Create callback was run, than yes, that is correct.
  2. If by " context of the original calling thread " you mean the thread that issued the original create operation, then no, you can’t assume that. Whether this makes a difference for your application depends on what you’re trying to do.

* by “all the minifilters” I mean all the minifilters in the frames between the filter that changed the context and the next filter that would change the context again.

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

Thank you very much Alex,

xxxxx@microsoft.com wrote:

Hello all,

Synchronizing to the original thread does not disable cancellable creates if the proper wait functions are used (see the documentation for FsRtlCancellableWaitForSingleObject for example).

Filter manager guarantees that the in the case of creates (as well as any synchronized operation) the post callback will be called in the same context as the pre callback. If another filter (it would have to be a legacy filter, I don’t see how a minifilter could do this) changes the thread context above filter manager then that’s the context both the pre and post callbacks will be called (if the operation is synchronized). In the thread mentioned above (http://www.osronline.com/showThread.cfm?link=109469), Tony’s filter could change the context above a certain filter manager frame (for the frames above Tony’s filter, if any, it wouldn’t matter) but then both the pre and the post callback for all the minifilters* would still be called in the same context (which is Tony’s filter new context).

So, Sandor, when you say " Yes, in a minifilter I can get the PRE-Create and POST-Create in a different thread " there are two possible interpretations:

  1. the contexts are different for pre and post (which cannot happen)
  2. the contexts are the same for pre and post, but it’s not the same thread that issued the original create (which can happen).

I was thinking about interpretation 2 :-).

The same two interpretations apply to the original question:
" Can somebody confirm that a POST-Create callback in a minifilter is always called at PASSIVE_LEVEL and *in the context of the original calling thread*?"

  1. If by " context of the original calling thread " you mean the thread where the PRE-Create callback was run, than yes, that is correct.
  2. If by " context of the original calling thread " you mean the thread that issued the original create operation, then no, you can’t assume that. Whether this makes a difference for your application depends on what you’re trying to do.

I was also thinking about case 2, so my assumption was wrong here (but,
after putting all pieces together it was clear to be wrong). However,
one question remains. The DDK states “FltGetRequestorProcessId returns
the process ID for the process associated with the thread that
originally requested the I/O operation.” Until now, I assumed that this
PID is the PID of the original requestor process.

However, now I think that this is generally the case only because the
above filters do not change the thread / process context for a create,
so it remains the same. Am I correct if I say, that in the case a filter
above would change the thread & process context, then I would receive
the new PID and not the original? (This would somehow mean, that the
filter above is plainly broken as it can very easily change the whole
system’s behavior…)

Or, another case: would PsGetCurrentProcessId return the current PID (of
the process context to which the above filter changed) and
FltGetRequestorProcessId the original PID (meaning that my initial
assumption was still right)?

thank you, have a nice day,

Sandor

Hi Sandor,

Let address your questions directly:

“Am I correct if I say, that in the case a filter above would change the thread & process context, then I would receive the new PID and not the original?”
This depends on the function you call: PsGetCurrentProcessId() returns the current process id while FltGetRequestorProcessId will get the original process ID

“would PsGetCurrentProcessId return the current PID (of the process context to which the above filter changed) and FltGetRequestorProcessId the original PID (meaning that my initial assumption was still right)”
Yes they would.

This works because in the general case some IRPs need to store some information about the original context since due to the asynchronous nature of the IO system the original context might be different by the time they get completed. For example, when the IO manager needs to queue an APC in the context of the originating thread, it must know somehow which thread it was. The point I’m trying to make is that regardless of how many times the context changes for the IRP, some information about the original context must be saved (sometimes, for some operations… and the information that is saved can be different for different IRP types :)).

Search MSDN for IoGetRequestorProcessId as it has a couple more documentation pointers. However, please note that filter manager doesn’t use that function internally so don’t make any assumptions in your code!!!

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

Thank you very-very much,

Sandor

xxxxx@microsoft.com wrote:

Hi Sandor,

Let address your questions directly:

“Am I correct if I say, that in the case a filter above would change the thread & process context, then I would receive the new PID and not the original?”
This depends on the function you call: PsGetCurrentProcessId() returns the current process id while FltGetRequestorProcessId will get the original process ID

“would PsGetCurrentProcessId return the current PID (of the process context to which the above filter changed) and FltGetRequestorProcessId the original PID (meaning that my initial assumption was still right)”
Yes they would.