Irp->Cancel is getting set. Do I Complete the Irp?

I have a routine that places a Irp into a Queue.
In this routine I set a IoCancelRoutine() for the
Irp then immediately check to see if Irp->Cancel
is set. If it is set I update the IoStatus to
STATUS_CANCELLED and call IoCompleteRequest() on
the Irp. Otherwise I trickle a STATUS_PENDING
back up through my code.

Is this correct behavior, completing the Irp.
I’m still a bit rusty on the Cancel process.

> I have a routine that places a Irp into a Queue.

In this routine I set a IoCancelRoutine() for the
Irp then immediately check to see if Irp->Cancel
is set. If it is set I update the IoStatus to
STATUS_CANCELLED and call IoCompleteRequest() on
the Irp. Otherwise I trickle a STATUS_PENDING
back up through my code.

Is this correct behavior, completing the Irp.
I’m still a bit rusty on the Cancel process.

What you describe is not complete. The whole process is pretty involved
(too involved to explain here properly) and easy to get wrong. I would
highly suggest you check out Walter Oney’s “Programming The Windows Driver
Model” 2nd Ed. to answer your questions. Walter has provided a very
detailed and complete discussion of I/O cancellation in that book.


Bill McKenzie
Compuware Corporation
Watch your IRPs/IRBs/URBs/SRBs/NDIS pkts with our free WDMSniffer tool:
http://frontline.compuware.com/nashua/patches/utility.htm

Implemented correctly, (and you should search for cancel safe queues in the
ddk,) once you set IoSetCancelRoutine with a non-null value it is your
cancel routine that should be responsible for cancelling the irp. There are
other algorithms, a lot of which spend a lot of time checking the cancel
flag, all of which either rely on the use of the system global cancel
spinlock or are hopelessly broken. Without more than your rather vague
description of your cancel processing, the best I can say is that it sounds
wrong to me.

=====================
Mark Roddy
Hollis Technology Solutions
www.hollistech.com
xxxxx@hollistech.com

-----Original Message-----
From: David [mailto:xxxxx@weibeltech.com]
Sent: Tuesday, July 15, 2003 9:09 AM
To: Windows System Software Developers Interest List
Subject: [ntdev] Irp->Cancel is getting set. Do I Complete the Irp?

I have a routine that places a Irp into a Queue.
In this routine I set a IoCancelRoutine() for the
Irp then immediately check to see if Irp->Cancel
is set. If it is set I update the IoStatus to
STATUS_CANCELLED and call IoCompleteRequest() on
the Irp. Otherwise I trickle a STATUS_PENDING
back up through my code.

Is this correct behavior, completing the Irp.
I’m still a bit rusty on the Cancel process.


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

Correct logic:

  1. Putting IRP to the queue:

KeAcquireSpinLock(&QueueLock);
IoSetCancelRoutine(Irp, YourCancel);
if( Irp->Cancel && ( IoSetCancelRoutine(Irp, NULL) != NULL ) )
{
KeReleaseSpinLock(&QueueLock);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_CANCELLED;
}
// put to the queue here
KeReleaseSpinLock(&QueueLock);

  1. Detaching the IRP from the queue:

KeAcquireSpinLock(&QueueLock);
Irp = FirstIrpInTheQueue;
for(;:wink:
{
if( IoSetCancelRoutine(Irp, NULL) != NULL )
{
// detach the IRP from the queue
KeReleaseSpinLock(&QueueLock);
return Irp;
}
if( Irp is last IRP in the queue )
break;
Irp = NextIrpInQueue(Irp);
}
KeReleaseSpinLock(&QueueLock);
return NULL;

  1. YourCancel routine:

IoReleaseCancelSpinLock(Irp->CancelIrql);
KeAcquireSpinLock(&QueueLock);
// detach the IRP from the queue
KeReleaseSpinLock(&QueueLock);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT)

Max

----- Original Message -----
From: “David”
To: “Windows System Software Developers Interest List”

Sent: Tuesday, July 15, 2003 5:08 PM
Subject: [ntdev] Irp->Cancel is getting set. Do I Complete the Irp?

> I have a routine that places a Irp into a Queue.
> In this routine I set a IoCancelRoutine() for the
> Irp then immediately check to see if Irp->Cancel
> is set. If it is set I update the IoStatus to
> STATUS_CANCELLED and call IoCompleteRequest() on
> the Irp. Otherwise I trickle a STATUS_PENDING
> back up through my code.
>
> Is this correct behavior, completing the Irp.
> I’m still a bit rusty on the Cancel process.
>
> —
> You are currently subscribed to ntdev as: xxxxx@storagecraft.com
> To unsubscribe send a blank email to
xxxxx@lists.osr.com

> cancel routine that should be responsible for cancelling the irp.
There are

other algorithms, a lot of which spend a lot of time checking the
cancel
flag, all of which either rely on the use of the system global
cancel

No. Irp->Cancel flag check does not require the cancel spinlock, and
is a good idea.

Imagine that CPU1 will call IoCancelIrp for the IRP which is in the
beginning of the driver’s dispatch function running on CPU0, before
the dispatch function have called IoSetCancelRoutine.

Without the Irp->Cancel check, the act of cancellation will be just
forgotten, and the IRP will be queued till its normal completion. For
things like serial or USB reads (polls, like MOUSER does), this can be
a disaster which will not allow the driver to shut down till the
hardware will send a byte.

Max

… and reverse the order of things. Be nice to by yourself and check
Irp->Cancel BEFORE you set the cancel routine.


Gary G. Little
Seagate Technologies, LLC
xxxxx@seagate.com

“Bill McKenzie” wrote in message
news:xxxxx@ntdev…
>
> > I have a routine that places a Irp into a Queue.
> > In this routine I set a IoCancelRoutine() for the
> > Irp then immediately check to see if Irp->Cancel
> > is set. If it is set I update the IoStatus to
> > STATUS_CANCELLED and call IoCompleteRequest() on
> > the Irp. Otherwise I trickle a STATUS_PENDING
> > back up through my code.
> >
> > Is this correct behavior, completing the Irp.
> > I’m still a bit rusty on the Cancel process.
>
> What you describe is not complete. The whole process is pretty involved
> (too involved to explain here properly) and easy to get wrong. I would
> highly suggest you check out Walter Oney’s “Programming The Windows Driver
> Model” 2nd Ed. to answer your questions. Walter has provided a very
> detailed and complete discussion of I/O cancellation in that book.
>
> –
> Bill McKenzie
> Compuware Corporation
> Watch your IRPs/IRBs/URBs/SRBs/NDIS pkts with our free WDMSniffer tool:
> http://frontline.compuware.com/nashua/patches/utility.htm
>
>
>

“Gary G. Little” wrote:

… and reverse the order of things. Be nice to by yourself and check
Irp->Cancel BEFORE you set the cancel routine.

Actually, no. The bulletproof logic I worked out long ago involves
setting the cancel pointer, testing Cancel, and (if it’s set) doing a
second IoSetCancelRoutine. That’s an atomic operation, and its return
value (NULL or not NULL) tells you whether IoCancelIrp got there in the
intervening few nanoseconds. If it did, you let your cancel routine
complete the IRP. If it didn’t, you complete the IRP.


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

> … and reverse the order of things. Be nice to by yourself and
check

Irp->Cancel BEFORE you set the cancel routine.

This - by itself - is not a solution, since there will be a window
between checking ->Cancel and IoSetCancelRoutine.

IoCancelIrp arrived to this window will be just ignored, which is a
Bad Thing for drivers which use the poll IRPs - like MOUSER or USB
interrupt pipes.

If USB stack and SERIAL would use your approach - then no way of
reliably cancelling the IRP -> no way of unloading the mouse or USB
device (including all HID devices) driver.

Max

> This - by itself - is not a solution, since there will be a window

between checking ->Cancel and IoSetCancelRoutine.

The assumption that the cancel routine will take the same spinlock as that
held when the cancel routine is put into the IRP must be made. In this
case all is fine. The cancel routine will drop the system cancel spinlock
immediately, then grab the driver’s spinlock. For this solution to work,
a winner has to be determined, that is who will complete the IRP, in
general the easiest way is to always let the cancel routine win.

If USB stack and SERIAL would use your approach - then no way of
reliably cancelling the IRP -> no way of unloading the mouse or USB
device (including all HID devices) driver.

Max

Here in is the rub and why I didn’t want to waste my time posting code and
trying to explain before. This is a rather BROAD topic, too broad to
cover properly here. IRP cancellation requires the cooperation of
dispatch routines, queue routines, cancel routines, StartIo routines,
sometimes ISRs and DPCs, routines all over the driver. Cancellation for
IRPs being put in a queue is quite a bit simpler and different than that
for in-progress IRPs.

All in all, I would suggest you go buy Walter Oney’s book, look at his
samples and try to understand them. And/or go get a good toolkit like
DriverWorks and look through its samples or wizard generated code which
uses queues and cancellation. Once you understand how cancellation and
queues work together, then go look at the DDK serial sample. The DDK
serial sample is AFAIK the only sample of in-progress cancelable IRPs
available. The serial sample is HIGHLY instructive.

Once you completely, or mostly understand the DDK serial sample, you will
be answering more questions here than you ask :slight_smile: Of course getting to
that point takes quite a while. What you are asking is a BIG question.


Bill McKenzie
Compuware Corporation
Watch your IRPs/IRBs/URBs/SRBs/NDIS pkts with our free WDMSniffer tool:
http://frontline.compuware.com/nashua/patches/utility.htm

> > This - by itself - is not a solution, since there will be a window

> between checking ->Cancel and IoSetCancelRoutine.

The assumption that the cancel routine will take the same spinlock
as that
held when the cancel routine is put into the IRP must be made. In
this
case all is fine. The cancel routine will drop the system cancel
spinlock
immediately, then grab the driver’s spinlock. For this solution to
work,
a winner has to be determined, that is who will complete the IRP, in
general the easiest way is to always let the cancel routine win.

Yes, you’re correct in terms of “nothing will crash”.

Nevertheless, there is a window between checking ->Cancel and
IoSetCancelRoutine. If IoCancelIrp will arrive in this window - then
it will just be ignored. Yes, nothing will crash, but the things will
go bad nevertheless.

Holding the device queue spinlock will not help in this.

All in all, I would suggest you go buy Walter Oney’s book, look at
his
samples and try to understand them.

Yes, very good cancellation-related samples.

Max

Oops, I thought you were criticizing the code I saw posted. That was your
code :slight_smile: I agree completely, the original poster’s solution is not
sufficient.


Bill McKenzie
Compuware Corporation
Watch your IRPs/IRBs/URBs/SRBs/NDIS pkts with our free WDMSniffer tool:
http://frontline.compuware.com/nashua/patches/utility.htm

> > This - by itself - is not a solution, since there will be a window
> > between checking ->Cancel and IoSetCancelRoutine.
>
> The assumption that the cancel routine will take the same spinlock
as that
> held when the cancel routine is put into the IRP must be made. In
this
> case all is fine. The cancel routine will drop the system cancel
spinlock
> immediately, then grab the driver’s spinlock. For this solution to
work,
> a winner has to be determined, that is who will complete the IRP, in
> general the easiest way is to always let the cancel routine win.

Yes, you’re correct in terms of “nothing will crash”.

Nevertheless, there is a window between checking ->Cancel and
IoSetCancelRoutine. If IoCancelIrp will arrive in this window - then
it will just be ignored. Yes, nothing will crash, but the things will
go bad nevertheless.

Holding the device queue spinlock will not help in this.

> All in all, I would suggest you go buy Walter Oney’s book, look at
his
> samples and try to understand them.

Yes, very good cancellation-related samples.

Max