WdfRequestIsCanceled vs. WdfIoQueueDispatchManual

Hi,

I see a strange BSOD. I have a manually managed queue, create it this way:

WDF_IO_QUEUE_CONFIG_INIT(&q_cfg, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(fdx->device, &q_cfg, NULL, &fdx->my_queue);

I store the requests for specific ioctl in the queue, and when I get a notification from device, I complete the request.

When I get a request from the framework, I check it in EvtIoInCallerContext, and then call for WdfDeviceEnqueueRequest.
When I get my EvtIoct function, I call for WdfRequestIsCanceled to check if request is not cancelled yet, and then call for WdfRequestForwardToIoQueue(request, fdx->my_queue).

Then I have the BSOD with PAGE_FAULT_IN_NONPAGED_AREA (50). The address points to request context that, and when running wdfrequest I get the following:

1: kd> !wdfkd.wdfrequest 0x7a352b40
!IRP 0x00000000
irp is NULL, the remaining results may not be correct(Reserved Requests may have a NULL IRP)…

State: Completed, Allocated by WDF for incoming IRP

My questions are:

  • Is it possible that the request was cancelled and I didn’t get it from some reason?
  • Should I cancel the request by myself if my io queue is manually dispatched? Can’t I count on framework that it will cancel the requests if I didn’t register the EvtIoCanceledOnQueue callback?

Thanks,
S.

xxxxx@gmail.com wrote:

I see a strange BSOD. I have a manually managed queue, create it this way:

WDF_IO_QUEUE_CONFIG_INIT(&q_cfg, WdfIoQueueDispatchManual);
status = WdfIoQueueCreate(fdx->device, &q_cfg, NULL, &fdx->my_queue);

I store the requests for specific ioctl in the queue, and when I get a notification from device, I complete the request.

When I get a request from the framework, I check it in EvtIoInCallerContext, and then call for WdfDeviceEnqueueRequest.
When I get my EvtIoct function, I call for WdfRequestIsCanceled to check if request is not cancelled yet, and then call for WdfRequestForwardToIoQueue(request, fdx->my_queue).

Then I have the BSOD with PAGE_FAULT_IN_NONPAGED_AREA (50). The address points to request context that, and when running wdfrequest I get the following:

1: kd> !wdfkd.wdfrequest 0x7a352b40
!IRP 0x00000000
irp is NULL, the remaining results may not be correct(Reserved Requests may have a NULL IRP)…

State: Completed, Allocated by WDF for incoming IRP

My questions are:

  • Is it possible that the request was cancelled and I didn’t get it from some reason?
  • Should I cancel the request by myself if my io queue is manually dispatched? Can’t I count on framework that it will cancel the requests if I didn’t register the EvtIoCanceledOnQueue callback?

Are you expecting the request to be canceled? Requests are not just
canceled out of the blue. Unless you are terminating the application, I
wouldn’t expect this to be a cancellation problem.

Are you running with driver verifier? That turns on a large number of
additional validation tests within KMDF.

Are you completing the request at any point? Remember that you EITHER
complete it or put it on a queue, not both. Perhaps you should show us
your code.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

You are probably looking at WDFREQUEST at corrupt/wrong address.

Satya
http://www.winprogger.com

Hi Tim,

Are you expecting the request to be canceled? Requests are not just canceled out of the blue. Unless
you are terminating the application, I wouldn’t expect this to be a cancellation problem.
The requests are sent and cancelled by third-party UMDF driver (my guess that they are cancelled, it’s possible that third party app is terminated because of the bug).

Are you running with driver verifier? That turns on a large number of additional validation tests
within KMDF.
Yep.

Are you completing the request at any point? Remember that you EITHER
complete it or put it on a queue, not both. Perhaps you should show us
your code.
I forward the request to my queue. When I get a notification from the device, I retrieve it back from the queue and then complete it.

Perhaps you should show us your code.
Here is the code for completing the request:

WdfSpinLockAcquire(fdx->spinlock);
status = WdfIoQueueRetrieveNextRequest(fdx->my_queue, &request);
WdfSpinLockRelease(fdx->spinlock);
if (!NT_SUCCESS(status))
{
ASSERT(status == STATUS_NO_MORE_ENTRIES);
DbgPrint((“%s: no pending WAIT ENCAPSULATED RESPONSE\n”, FUNCTION));
return;
}

status = GetRequestCtx(request, &req_ctx);
if (!NT_SUCCESS(status))
{
DbgPrint((“%s: Could not get request memory buffer %lx\n”,
FUNCTION, status));
return;
}

status = UpdateRequestCtx(&req_ctx);
WdfRequestCompleteWithInformation(request, status, sizeof(req_ctx));

Thanks,
S.

xxxxx@gmail.com wrote:

> Are you completing the request at any point? Remember that you EITHER
> complete it or put it on a queue, not both.
I forward the request to my queue. When I get a notification from the device, I retrieve it back from the queue and then complete it.

> Perhaps you should show us your code.
Here is the code for completing the request:

I thought you said the crash was happening when you forwarded it to the
queue. In that case, how could it possibly help us to look at the
completion code? You haven’t reached that point yet.

WdfSpinLockAcquire(fdx->spinlock);
status = WdfIoQueueRetrieveNextRequest(fdx->my_queue, &request);
WdfSpinLockRelease(fdx->spinlock);
if (!NT_SUCCESS(status))
{
ASSERT(status == STATUS_NO_MORE_ENTRIES);
DbgPrint((“%s: no pending WAIT ENCAPSULATED RESPONSE\n”, FUNCTION));
return;
}

status = GetRequestCtx(request, &req_ctx);
if (!NT_SUCCESS(status))
{
DbgPrint((“%s: Could not get request memory buffer %lx\n”,
FUNCTION, status));
return;
}

status = UpdateRequestCtx(&req_ctx);
WdfRequestCompleteWithInformation(request, status, sizeof(req_ctx));

One thing to note here: if GetRequestCtx fails, you return without
completing the request. That will leave it dangling forever. No one
will ever complete it.

I’m curious about what this code is supposed to do. Usually, we use the
term “request context” to refer to a KMDF context structure that we
attached to the request. In that case, it wouldn’t make any sense to
return sizeof(req_ctx) as the “information” value, because you haven’t
really copied anything into the IRP’s output buffer.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

*I’m* wondering why there’s a spin lock protecting WdfIoQueueRetrieveNextRequest…

Peter
OSR

Also, why do you need an in caller context callback? The only reason to have one is to probe and lock method neither buffers and I don’t thinkg the UMDF client driver is doing that.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, October 21, 2010 10:24 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] WdfRequestIsCanceled vs. WdfIoQueueDispatchManual

Hi Tim,

Are you expecting the request to be canceled? Requests are not just
canceled out of the blue. Unless you are terminating the application, I wouldn’t expect this to be a cancellation problem.
The requests are sent and cancelled by third-party UMDF driver (my guess that they are cancelled, it’s possible that third party app is terminated because of the bug).

Are you running with driver verifier? That turns on a large number of
additional validation tests within KMDF.
Yep.

Are you completing the request at any point? Remember that you EITHER
complete it or put it on a queue, not both. Perhaps you should show
us your code.
I forward the request to my queue. When I get a notification from the device, I retrieve it back from the queue and then complete it.

Perhaps you should show us your code.
Here is the code for completing the request:

WdfSpinLockAcquire(fdx->spinlock);
status = WdfIoQueueRetrieveNextRequest(fdx->my_queue, &request);
WdfSpinLockRelease(fdx->spinlock);
if (!NT_SUCCESS(status))
{
ASSERT(status == STATUS_NO_MORE_ENTRIES);
DbgPrint((“%s: no pending WAIT ENCAPSULATED RESPONSE\n”, FUNCTION));
return;
}

status = GetRequestCtx(request, &req_ctx);
if (!NT_SUCCESS(status))
{
DbgPrint((“%s: Could not get request memory buffer %lx\n”,
FUNCTION, status));
return;
}

status = UpdateRequestCtx(&req_ctx);
WdfRequestCompleteWithInformation(request, status, sizeof(req_ctx));

Thanks,
S.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Hi All,

Thank you for replies.

One thing to note here: if GetRequestCtx fails, you return without
completing the request. That will leave it dangling forever. No one
will ever complete it.
Thanks for pointing to that. I never saw that happens, but I’ll fix it anyway.
As for the rest of the code, all I do is to call for
WdfRequestForwardToIoQueue(request, fdx->my_queue)
from my EvtIoctl func.

*I’m* wondering why there’s a spin lock protecting
WdfIoQueueRetrieveNextRequest…
Just my code-specific paranoya, discard it :slight_smile:

Also, why do you need an in caller context callback?
Well, I get a buffer from third party, which I lock in the in caller callback and store it within the request context. When I get data from device, I store it within that buffer.

My original question is: how could I get the WdfRequestIsCanceled returning FALSE, and having request’s IRP = NULL?
Also: if the request is cancelled by framework when it’s still in my queue, will the framework remove it from the queue, or I should call for WdfRequestIsCanceled to check if the request is cancelled after I retrieve it using WdfIoQueueRetrieveNextRequest?

Thanks,
S.