none
Cancel confusion: What if WdfRequestUnmarkCancelable returns STATUS_CANCELLED? RRS feed

  • Question

  • The documentation for WdfRequestUnmarkCancelable claims the following:

    If WdfRequestUnmarkCancelable returns a value other than STATUS_CANCELLED, the driver's EvtRequestCancel callback function will not be called for the request.

    If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, and then EvtRequestCancel completes the request, the driver must not subsequently use the request object.

    If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, the driver must not complete the request before the framework calls EvtRequestCancel. Otherwise, the framework might call the driver's EvtRequestCancel with an invalid request.


    However, what now happens is this:

    - Framework calls EvtRequestCancel for a request.

    - In the EvtRequestCancel I set a flag for the DPC to cancel the request and then queue the DPC. This prevents races with the IRQ handling and hardware control.

    - The DPC resets the hardware and then calls "WdfRequestUnmarkCancelable" for the request

    - WdfRequestUnmarkCancelable returns STATUS_CANCELLED.

    Nothing happens after that. I cannot report the request as "cancelled" in the DPC, because the documentation says so. But the EvtRequestCancel has already run and won't be called again.

    Now what am I supposed to do here?

    (Yes, I know about manual IO queues, but the request has arrived in hardware so it cannot be in a manual queue, right?)

    Monday, July 18, 2016 6:34 AM

Answers

  • The critical part of the documentation is "If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, the driver must not complete the request before the framework calls EvtRequestCancel."  In your case you know the EvtRequestCancel is called because that is what is triggering the  DPC which you then are calling WdfRequestUnmarkCancelable in.  Yes, you have changed thread context, but the actual cancel processing is part of the actions triggered by EvtRequestCancel, so the documentation is correct, though perhaps not as clear as it could be.

    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Tuesday, July 19, 2016 12:47 PM

All replies

  • you need to record that EvtRequestCancel has run b/c somewhere in your state (probably near where you set the flag for the DPC to cancel). then in the dpc you look at the flag and complete the request since without unmarking it as it has already been canceled

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Monday, July 18, 2016 6:41 AM
  • Since EvtRequestCancel is the one that sends the cancel request to the DPC, and since the driver itself won't spontaneously cancel requests, the DPC can thus ALWAYS complete the request, regardless of what WdfRequestUnmarkCancelable returns?

    Monday, July 18, 2016 7:19 AM
  • How do you know your driver is the one canceling the request?  If the request comes from user space it can be canceled by the application program calling your driver.  If the request is passed to a driver stack then the request can be canceled by some other driver in the stack.   In general you have to assume that a request can be canceled without your control.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Monday, July 18, 2016 10:59 AM
  • I don't understand your question. My driver does not cancel requests on its own, it only responds to the framework sending a cancel request through the callback.

    Are you telling me that requests can get cancelled without calling my EvtRequestCancel callback?

    https://msdn.microsoft.com/en-us/library/ff549984%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

    "When calling WdfRequestMarkCancelableEx, your driver must specify an EvtRequestCancel callback function. The framework calls the callback function if the I/O manager or another driver is attempting to cancel the I/O request."

    If the request is in a queue, it can be "dropped" anytime.

    In the IO callback, before the hardware starts working on it, I've marked it cancelable. The only way to cancel it from that point is through the provided EvtRequestCancel callback. So at that point, the request either completes on itself, or gets cancelled through that callback. My understanding so far is that there's no "backdoor" here that could cancel requests in hardware without my driver knowing about it. But I could be wrong, so please explain.

    Monday, July 18, 2016 11:21 AM
  • Adding to what Doron wrote, it sounds like you are unnecessarily calling WdfRequestUnmarkCancelable. EvtRequestCancel is your async notification that someone wants your request canceled. This callback hands you the request and you own the request until you complete it. The request in this case is already cancelled so you don’t need to call WdfRequestUnmarkCancelable, you just need to complete it with STATUS_CANCELLED once you have guaranteed no one else will complete the request.

    Monday, July 18, 2016 9:43 PM
  • The documentation clearly states:

    If a driver has called WdfRequestMarkCancelableEx, and if the driver's EvtRequestCancel callback function has not executed and called WdfRequestComplete, the driver must call WdfRequestUnmarkCancelable before it calls WdfRequestComplete outside of the EvtRequestCancel callback function.


    Which to me means that I still have to call WdfRequestUnmarkCancelable because i'm doing it outside the callback.

    Tuesday, July 19, 2016 5:16 AM
  • Your basic problem is given the steps you enumerated:

    1. Framework calls EvtRequestCancel for a request.

    2. In the EvtRequestCancel I set a flag for the DPC to cancel the request and then queue the DPC. This prevents races with the IRQ handling and hardware control.

    3. The DPC resets the hardware and then calls "WdfRequestUnmarkCancelable" for the request

    4. WdfRequestUnmarkCancelable returns STATUS_CANCELLED.

    In step one the request is CANCELLED just because you put a DPC in the process you have still seen the EvtRequestCancel for the request, but now in step 4 you want to make the cancelled request as not being cancelable!   Of course it is going to tell you the request has been cancelled.

    This is what Doron and Wes were trying to say, just packaged in a different manner.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Tuesday, July 19, 2016 11:04 AM
  • So the documentation is wrong then? Because it really says that I have to call WdfRequestUnmarkCancelable if I don't complete it inside the callback.

    So what MS wanted to tell me is actually that the framework already called WdfRequestUnmarkCancelable before it entered the callback?

    Experience has shown that not calling WdfRequestUnmarkCancelable when I should have results in a BSOD. Calling it too often just results in an error code return. So I'm reluctant to deviate from what the documenation says.

    I guess I'll keep some statistics and see if WdfRequestUnmarkCancelable ever returns anything else but STATUS_CANCELED.

    Tuesday, July 19, 2016 12:30 PM
  • The critical part of the documentation is "If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, the driver must not complete the request before the framework calls EvtRequestCancel."  In your case you know the EvtRequestCancel is called because that is what is triggering the  DPC which you then are calling WdfRequestUnmarkCancelable in.  Yes, you have changed thread context, but the actual cancel processing is part of the actions triggered by EvtRequestCancel, so the documentation is correct, though perhaps not as clear as it could be.

    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Tuesday, July 19, 2016 12:47 PM