Cancel routine not called for queued IRPs

An asynchronous IOCTL call occurs. The driver (using custom queues)
acquires a queues spin lock, calls IoSetCancelRoutine(…), calls
InsertTailList(…), sets the IRP status to STATUS_PENDING, and calls
IoCompleteRequest(…) for the IRP.

These queued IRPs are usually completed in the DpcForIsr routine. If
device interrupts aren’t occurring then the IRPs stay queued indefinitely.
The exception to this is when the user app calls CancelIo(…) (from the
same thread as the DeviceIoControl(…) call). CancelIo(…) will be
called at app shutdown for example.

The problem lies in the fact that the cancel routine for the IRPs is not
being called. After the 5-minute timeout in the I/O Manager the IRPs are
cancelled and the application process exits.

What might be missing or wrong?

Eric Solberg wrote:

An asynchronous IOCTL call occurs. The driver (using custom queues)
acquires a queues spin lock, calls IoSetCancelRoutine(…), calls
InsertTailList(…), sets the IRP status to STATUS_PENDING, and calls
IoCompleteRequest(…) for the IRP.

I hope not! You should not be completing the IRP at this point, and it’s
a miracle that the system isn’t crashing when next you do an operation
on your queue.

There is a fully worked out set of functions for “IOCTL IRP caching” in
my driver book. I use those routines all the time, and the cancel
routine is definitely getting called at the right time.


Walter Oney, Consulting and Training
Basic and Advanced Driver Programming Seminars
Check out our schedule at http://www.oneysoft.com

Mr. Oney,

Why shouldn’t the IRPs status be set to STATUS_PENDING and
IoCompleteRequest(…) be called for an asynchronous IOCTL? The IRPs
cancel routine has been set and the IRP placed on the custom queue prior
to that.

Thank you.

Because you should not COMPLETE the request until it is complete.
Putting it in a queue means it isn’t complete. After you call
IoCompleteRequest, you should not touch/use/dereference the IRP pointer
again – when you call IoCompleteRequest, you are transferring control
of the IRP back to the originator of the IRP. The originator will most
likely examine the completion status, then destroy the IRP.

If you put an IRP on a queue/list/whatever, you should call
IoMarkIrpPending, then return STATUS_PENDING. Once you remove the IRP
from your internal queue, process it, and are ready to complete it –
THAT is when you should call IoCompleteRequest.

– arlie

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Eric Solberg
Sent: Friday, September 26, 2003 2:28 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Re: Cancel routine not called for queued IRPs

Mr. Oney,

Why shouldn’t the IRPs status be set to STATUS_PENDING and
IoCompleteRequest(…) be called for an asynchronous IOCTL? The IRPs
cancel routine has been set and the IRP placed on the custom queue prior
to that.

Thank you.


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@sublinear.org To
unsubscribe send a blank email to xxxxx@lists.osr.com

Arlie Davis wrote:

If you put an IRP on a queue/list/whatever, you should call
IoMarkIrpPending, then return STATUS_PENDING. Once you remove the IRP
from your internal queue, process it, and are ready to complete it –
THAT is when you should call IoCompleteRequest.

And in addition, STATUS_PENDING is a silly value to put into
IoStatus.Status. It’s only use is as a return value from a dispatch
routine.


Walter Oney, Consulting and Training
Basic and Advanced Driver Programming Seminars
Check out our schedule at http://www.oneysoft.com

Get Walter’s WDM 2nd Edition book and read it a couple of times. You don’t
understand IRPs and how they work. Start with a tutorial. The biggest clue
is the “Complete” in IoCompleteRequest() which means done, gone, bye bye,
and implies not yours anymore.

“Eric Solberg” wrote in message
news:xxxxx@ntdev…
>
> Mr. Oney,
>
> Why shouldn’t the IRPs status be set to STATUS_PENDING and
> IoCompleteRequest(…) be called for an asynchronous IOCTL? The IRPs
> cancel routine has been set and the IRP placed on the custom queue prior
> to that.
>
> Thank you.
>
>

Based on the input from Mr. Oney, reading the DDK for
IoCompleteRequest(…), and looking at several books on drivers including
Mr. Oney’s, I’ve come up with following:

  • IoCompleteRequest(…) should be called only once per IRP. Trying to
    complete an IRP more than once is a definite problem and should bugcheck
    the system.

  • When working with an asynchronous IOCTL the author should set the IRP
    just call IoMarkIrpPending(…) and the StartPacket(…) routine for the
    driver. The StartPacket routine must place the IRP in the drivers custom
    queue. Finally the dispatch routine should return STATUS_PENDING without
    completing the IRP.

This should solve the problem of the IRPs cancel routine not getting
called.