RE: [ntdev]Walter Owney's code for IoCancelIrp

MessageMark, you're answering the wrong question. You must not call IoCancelIrp unless you are
guaranteeing that the IRP will not be completed and freed during that call (i.e., it can be completed,
but not freed). Consider:

"If Irp->CancelRoutine is NULL, and therefore the IRP is not cancelable, IoCancelIrp sets the IRP's cancel bit and returns FALSE. The IRP should be canceled at a later time when it becomes cancelable."

Obviously if the IRP has been freed when the IoCancelIrp gets around to setting the Cancel flag is set, you are in for lots of trouble.

This is not something the called driver can do, it's only something the driver that allocated the IRP can do. (Since the IOM usually allocates IRPs that are cancelled, the IOM obviously worries about this case.)

-DH

PS. The MS strategy for Cancel has always be bug prone. It would have been better it the cancel semantics were something like the IRP creator sets "Cancel" while it holds appropriate locks, and the call to the lower level drivers was just "Cancel any Irp with the Cancel flag set". This would have removed the slew of race conditions the current definition make syou handle.
----- Original Message -----
From: Roddy, Mark
To: NT Developers Interest List
Sent: Friday, November 30, 2001 8:23 AM
Subject: [ntdev] RE: [ntdev]Walter Owney's code for IoCancelIrp

I don't know about Walter's code, but your cancel routine must be set to NULL before you call IoCompleteRequest. There are algorithms that use the return value of IoSetCancelRoutine to safely decide about how to deal with the race condition between calling IoSetCancelRoutine and the execution of your cancel routine. The idea is to in fact guarantee that if your cancel routine is running then the Irp parameter toyour cancel routine is valid, AND THE IRP IS ON A QUEUE. Here is a clue: if your call to IoSetCancelRoutine (the one you make prior to calling IoCompleteRequest that NULLS out your cancel routine pointer in the IRP) returns NULL, then your cancel routine is currently executing and you should not complete the IRP here, but instead rely on your cancel routine conmpleting it.

So your completion side looks something like:

devExt->LockIrpQueue();

Irp = devExt->getNextIrp();
CancelRoutine = IoSetCancelRoutine(Irp, NULL);
if (Irp == NULL) {
//
// oops, my cancel routine is about to complete this irp! put it on
// my cancel queue so my cancel routine can remove it from there
// NB we could use InitializeListHead also - but there would then be
// no way to debug these irps.
//
devExt->putIrpOnCancelQueue(Irp);

} else {
...// do some stuff
IoCompleteRequset(Irp, ...);

}

devExt->UnLockIrpQueue();

And your cancel routine does something like

IoReleaseCancelSpinlock(Irp->CancelIrql);
devExt->LockIrpQueue();
RemoveEntryList(Irp); // we guarantee it is on SOME queue.
devExt->UnLockIrpQueue();

Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, ...);
-----Original Message-----
From: Assaf Wodeslavsky [mailto:xxxxx@hotmail.com]
Sent: Friday, November 30, 2001 6:45 AM
To: NT Developers Interest List
Subject: [ntdev] [ntdev]Walter Owney's code for IoCancelIrp

hi all

Walter Oney says in his book page: 205
that IoCancelIrp uses the irp pointer

my question:
what if the irp has been completed by a StartIo-Isr-Dpc's
call to IoCompleteRequest?
this pointer would be stale!!!

Walter wrote me that if i think about it, i'll see that the irp is either null or valid
however
i thought about it
and
null it cant be - some one called IoCancelIrp with a valid irp - not null
valid - well what if it got completed by the driver?
it would be stale by the time IoCancelIrp got to it

thanks
assaf


You are currently subscribed to ntdev as: xxxxx@stratus.com
To unsubscribe send a blank email to leave-ntdev-$subst('Recip.MemberIDChar')@lists.osr.com

You are currently subscribed to ntdev as: xxxxx@syssoftsol.com
To unsubscribe send a blank email to leave-ntdev-$subst('Recip.MemberIDChar')@lists.osr.com


You are currently subscribed to ntdev as: $subst('Recip.EmailAddr')
To unsubscribe send a blank email to leave-ntdev-$subst('Recip.MemberIDChar')@lists.osr.com