IO Completion for IRP_MJ_CREATE is dispatch level?

WOW! I just saw some bad driver code I wanted to verify with OSR. It’s my driver but I didn’t code this part…yet responsible for it now. I’m not sure how it’s even working reliably which likely not. So just checking here at OSR to see if this is a misunderstanding on my part before I fix it. Basically, a dev changed the create dispatch method to set an IO Completion, and moved code which enters a fast mutex and as well (outside of mutex) calls ZwCreateFile to that IO Completion, both of which are taboo at dispatch level. So I’m just verifying with OSR forum that indeed IRP_MJ_CREATE IO completion is NOT guaranteed to run at passive level. In which case I need to post the work to a work thread which will run at passive level.


Hi Russel,

The documentation says a completion must be prepared to be executed at DISPATCH_LEVEL, but it is not guaranteed it will be called at DISPATCH_LEVEL. There is no exceptions or mentions about IRP_MJ_CREATE.

Although it is running fine today, it doesn’t mean it will always work. A completion routine is executed by the same thread some driver bellow yours called IoCompleteRequest. The documentation says IoCompleteRequest can be called on IRQL <= DISPATCH_LEVEL. So, even though the current underlying driver doesn’t change its behavior, a new filter might be attached to the File System bellow your filter. In this case, it’s up to this new filter to choose deffer IRP_MJ_CREATE completion and ending up calling IoCompleteRequest from a custom DPC. You’ll never know.

One thing you can do is:

  1. Move this code from the completion routine to an work item.
  2. Check the current IRQL on your completion routine.
  3. Depending on the IRQL, you can either queue an work item or call your work item routine directly from your completion routine.


Fernando Roberto da Silva
DriverEntry Kernel Development

There’s a verifier option to always return STATUS_PENDING.

Note that the I/O Manager doesn’t guarantee any function will complete below DISPATCH_LEVEL, and while it would be unusual for create, I’d be surprised if there weren’t cases where it completed at APC_LEVEL (or inside a KeEnterCriticalRegion call, disabling normal kernel APCs, or inside a guarded mutex, disabling all APCs but leaving you at passive level.) I did notice the Windows 8 environment is enforcing IRQL and APC correctness in calls to the ZwXxx APIs now, which is a good thing.

Filter Manager guarantees that post create will be called at PASSIVE level as I recall, but they do that by doing any work necessary to make that “just work” for you.


Thanks Fernando and Tony! I’ll be moving the work to a work item as suggested. Thanks again!

>mutex and as well (outside of mutex) calls ZwCreateFile to that IO Completion, both of which are

taboo at dispatch level.

Correct, this is a bug. ZwXxx stuff should be offloaded to a work item.

Maxim S. Shatskih
Windows DDK MVP