Well yes sure, I was dealing with the normal case where the IO manager
is canceling the IRP as a consequence of thread termination or user mode
invocation of CancelIrp, or the IRP owner is following the correct rules
(undocumented of course) for safely performing an IoCancelIrp request.
As far as I know there is no reliable way to deal with a kernel thread
that is calling IoCancelIrp and NOT behaving correctly. The best a
driver can do is to assume that the IRP is being managed correctly by
the IRP ‘owner’. Note that the documentation for IoCancelIrp alludes to
this problem:
"If a driver that does not own the IRP calls IoCancelIrp, the results
are unpredictable. The IRP might be completed with a successful status
even though its cancel bit was set.
An intermediate driver should not arbitrarily call IoCancelIrp unless
that driver created the IRP passed in the call. Otherwise, the
intermediate driver might cancel an IRP that some higher-level driver is
tracking for purposes of its own."
In my opinion exposing IoCancelIrp and not enforcing the rule that the
caller must own the IRP, was a mistake. Better yet, as you say, they
should have redesigned the whole mess.
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Dave Harvey
Sent: Sunday, December 02, 2001 12:03 AM
To: NT Developers Interest List
Subject: [ntdev] RE: [ntdev]Walter Owney’s code for IoCancelIrp
Mark, 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, mailto:xxxxx Mark
To: NT Developers Interest List mailto:xxxxx
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: xxxxx@hollistech.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</mailto:xxxxx></mailto:xxxxx>