Posting error status to IRP in a DPC hangs the driver.

I’ve got a perplexing problem.

I have a function F which takes an IRP, and does some stuff and completes the IRP after setting the Status and Information fields.

This occurs within a DeviceControl routine.

In some cases, there is an error in the request it is processing, and it then puts STATUS_INVALID_PARAMETER and 0 in the IRP fields.

If F is called directly by DeviceControl, and there is an error, things are fine, and the user client gets an error code of ‘the parameter is incorrect’.

However, I can also call F in a DPC’s deferred routine. DeviceControl returns STATUS_PENDING to the system, and the F completes the IRP within the DPC.

If F is called within the DPC and there is no error, things work fine, and I get the correct data back to the user client.

But, if F is called within the DPC and there is an error, the driver hangs. I cannot do SC STOP on the driver, and the user client hangs waiting for the DeviceControl function to return, and I cannot kill the process.

So apparently, the IoCompleteRequest isn’t working right.

Is there a possible race condition here, where the DPC executes as soon as it is queued and before the DispatchControl has a chance to return?

Is there a way I can use WinDbg in local mode to examine the state of my driver and see what is going on?

Do you call IoMarkIrpPending in DeviceControl before making the IRP might be completed by the DPC? Also, does your driver pass Driver Verifier?

For your other question, try LiveKD

https://docs.microsoft.com/en-us/sysinternals/downloads/livekd

-scott
OSR
@OSRDrivers

Yes… but Windows will handle this “race condition” for you, **as long as you’ve called IoMarkIrpPending and (eventually) return STATUS_PENDING from your dispatch entry point when you complete the request in your DPC, as Mr. Noone alluded to.

In other words, even if the DPC runs and completes the Request before your Dispatch Routine returns you’re OK, as long as:

  1. You’ve called IoMarkIrpPending BEFORE the DPC runs AND
  2. Your Dispatch Routine eventually returns STATUS_PENDING

Peter
OSR
@OSRDrivers

I put in the IoMarkIrpPending and the driver works fine now. Thanks for the pointer.

One further question… I call it before queueing the DPC. But what if the queue DPC fails? DispatchControl obviously will have to complete the DPC itself with some error code and return that error code. Is the IoMarkIrpPending going to cause problems?

Alternatively, could I call IoMarkIrpPending in the DPC itself?

xxxxx@rolle.name wrote:

One further question… I call it before queueing the DPC. But what if the queue DPC fails? DispatchControl obviously will have to complete the DPC itself with some error code and return that error code. Is the IoMarkIrpPending going to cause problems?

KeInsertQueueDpc cannot fail.  It either returns 1, meaning the DPC is
now queued, or it returns 0, meaning the DPC was already queued.  In
either case, the DPC function is going to run.

Alternatively, could I call IoMarkIrpPending in the DPC itself?

No, you have to call IoMarkIrpPending before your dispatch routine returns.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

>No, you have to call IoMarkIrpPending before your dispatch routine returns.

No, IoMarkIrpPending only needs to be called before the completion routine for this stack level returns. Its result is examined immediately after the completion routine returns.

The rule is that you *must* call IoMarkIrpPending *before* the IRP is available for processing and potential completion outside of your dispatch routine. You can’t COUNT on your DPC running before your Dispatch Routine returns, so… you cannot call IoMarkIrpPending in your DPC.

Don’t forget, you *must* return STATUS_PENDING from your dispatch routine as well. This is not optional.

Peter
OSR
@OSRDrivers

Alternatively buy Walter Oneys book and read his excellent chapters on IRP handing. There are about 9 ways of doing this. Each subtly different.