WDF filtering PnP IRP handling: What have I got wrong?

Hi folks,

I’ve probably made a silly error here, but I can’t work out what I’ve
done wrong. I get an error via driver verifier, but clearly WDF is
making my memory for the details of PnP Irp handling rather vague…

WDM DRIVER ERROR: [Wdf01000.sys @ 0xB97BE80D] A driver has returned
STATUS_PENDING but did not mark the IRP pending via a call
to IoMarkIrpPending (Irp = 8937CCF0).
IRP_MJ_PNP.IRP_MN_START_DEVICE
[ DevObj=875BEB80, FileObject=00000000, Parameters=E20F1C68 E12A1C00
00000000 00000000 ]
http://www.microsoft.com/hwdq/bc/default.asp?os=5.2.3790&major=0xc9&minor=0x24c&lang=0x9
Break, Ignore, Zap, Remove, Disable all (bizrd)? b

I’ve done:

status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit,

BusDevicePnpIrpFilter,
IRP_MJ_PNP,
NULL,
0);

static NTSTATUS
BusDevicePnpIrpFilter(
IN WDFDEVICE Device,
IN PIRP pIrp
)
{

pStack = IoGetCurrentIrpStackLocation(pIrp);
NT_ASSERT(pStack->MajorFunction == IRP_MJ_PNP);

BusDriverPrintPnPIrpDetails(Device, pIrp, pStack, TRUE, FALSE);


done:
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine( pIrp,
BusDriverDevPnPIrpCompletion,
NULL,
TRUE,
TRUE,
TRUE
);
return WdfDeviceWdmDispatchPreprocessedIrp(Device, pIrp);
}

NTSTATUS BusDriverDevPnPIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context) {
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(Irp);
WDFDEVICE Device = WdfWdmDeviceGetWdfDeviceHandle(DeviceObject);
PBUS_DEVICE_CONTEXT pPhysCtxt = BusDeviceGetContext(Device);
PBUS_SINGLETON_CONTEXT pVirtCtxt = BusSingletonGetContext(Device);
NT_ASSERT((pPhysCtxt != NULL) != (pVirtCtxt != NULL));

BusDriverPrintPnPIrpDetails(Device, Irp, pStack, (pPhysCtxt != NULL),
TRUE);

return STATUS_SUCCESS;
}

Martin Harvey wrote:

Hi folks,

I’ve probably made a silly error here, but I can’t work out what I’ve
done wrong. I get an error via driver verifier, but clearly WDF is
making my memory for the details of PnP Irp handling rather vague…

Doh! Idiot!

From MSDN:

If a driver sets an /IoCompletion/
http: routine for an
IRP and then passes the IRP down to a lower driver, the /IoCompletion/
routine should check the IRP->PendingReturned flag. If the flag is
set, the /IoCompletion/ routine must call IoMarkIrpPending with the
IRP. (/IoCompletion/ routines do not return STATUS_PENDING, however. For
more information, see Implementing an /IoCompletion/ Routine
http:.)

</http:></http:>

Plus ca change

On Jan 14, 2008 11:00 AM, Martin Harvey wrote:
> Martin Harvey wrote:
>
> > Hi folks,
> >
> > I’ve probably made a silly error here, but I can’t work out what I’ve
> > done wrong. I get an error via driver verifier, but clearly WDF is
> > making my memory for the details of PnP Irp handling rather vague…
> >
> Doh! Idiot!
>
> From MSDN:
>
> If a driver sets an /IoCompletion/
> http: routine for an
> IRP and then passes the IRP down to a lower driver, the /IoCompletion/
> routine should check the IRP->PendingReturned flag. If the flag is
> set, the /IoCompletion/ routine must call IoMarkIrpPending with the
> IRP. (/IoCompletion/ routines do not return STATUS_PENDING, however. For
> more information, see Implementing an /IoCompletion/ Routine
> http:.)
>
>
>
>
>
>
>
> —
> 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
>


Mark Roddy</http:></http:>

Mark Roddy wrote:

Plus ca change

Okay. Next question is: Why?

When the IRP intially gets dispatched, I can see how The I/O manager
would check for a return of STATUS_PENDING and also the pending bit to
decide whether to finish processing the IRP.

I’m can also see that the I/O manager uses the pending bit in the IRP on
completion to enable it to work out whether it can transfer results back
to the user app fairly synchronously, or whether it will need to
schedule an APC to do so (i.e. whether guaranteed in same process
context or not).

What I can’t understand is this:

  • When the completion routines get called for a pending IRP, say some
    time long after the irp was initially dispatched, why not just check the
    pending bit in the IRP - why do we need to effectively copy the
    PendingReturned bit back into all the stack locations in the completion
    routines?

The more I look at how IRP’s get processed the more it confuses me. Even
with the help of various scriptures written by the prophet Oney, there
are so many “funny cases” and “apparently arbitrary” rules…

MH.

[Begin quote]

From MSDN: If a driver sets an /IoCompletion/ http: routine for an IRP and then passes the IRP down to a lower driver, the /IoCompletion/ routine should check the IRP->PendingReturned flag. If the flag is set, the /IoCompletion/ routine must call IoMarkIrpPending with the IRP. (/IoCompletion/ routines do not return STATUS_PENDING, however. For more information, see Implementing an /IoCompletion/ Routine http:.)

[end quote]

1. You can also call IoMarkIrpPending() before passing it down the stack, and return STATUS_PENDING from your Dispatch routine regardless of IOCalDRiver()'s return value.
In such case you don’t have to call IoMarkIrpPending() in your Completion Routine, because you have already marked your stack location as pending…

2. The above MSDN quotation applies only if you have received IRP from another driver. If you have allocated it yourself, you will crash as a result of calling IoMarkIrpPending() in your completion routine(unless you have allocated an extra stack location in IRP, of course), because, after your completion routine returns, IoCompleteRequest() will unconditionally copy the bit to the next stack location if you have called IoMarkIrpPending() in it. Once no more stack locations are left in IRP, you are going to watch a BIG BANG!!!

Anton Bassov</http:></http:>

The pending bit may not need to be copied if the driver whose completion
routine is running is going to signal an event to let its dispatch routine
know the IRP has returned. That completion routine then returns
STATUS_MORE_PROCESSING_REQUIRED. The dispatch routine then completes the
IRP never setting the pending bit nor returning STATUS_PENDING. Forcing the
IoManager to schedule an APC when it is not required is a waste of
resources.

“Martin Harvey” wrote in message
news:xxxxx@ntdev…
> Mark Roddy wrote:
>
>>Plus ca change
>>
> Okay. Next question is: Why?
>
> When the IRP intially gets dispatched, I can see how The I/O manager would
> check for a return of STATUS_PENDING and also the pending bit to decide
> whether to finish processing the IRP.
>
> I’m can also see that the I/O manager uses the pending bit in the IRP on
> completion to enable it to work out whether it can transfer results back
> to the user app fairly synchronously, or whether it will need to schedule
> an APC to do so (i.e. whether guaranteed in same process context or not).
>
> What I can’t understand is this:
>
> - When the completion routines get called for a pending IRP, say some time
> long after the irp was initially dispatched, why not just check the
> pending bit in the IRP - why do we need to effectively copy the
> PendingReturned bit back into all the stack locations in the completion
> routines?
>
> The more I look at how IRP’s get processed the more it confuses me. Even
> with the help of various scriptures written by the prophet Oney, there are
> so many “funny cases” and “apparently arbitrary” rules…
>
> MH.
>
>

> - When the completion routines get called for a pending IRP, say some

time long after the irp was initially dispatched, why not just check the
pending bit in the IRP - why do we need to effectively copy the
PendingReturned bit back into all the stack locations in the completion
routines?

This is to handle something like - A pends the IRP, then sends it down to B, B
completes synchronously, then A pends again, then A completes.


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

> why do we need to effectively copy the PendingReturned bit

back into all the stack locations in the completion routines?

This is a good question that confused me quite a lot as a newbie…

Basically, when a driver calls IoCompleteRequest() on IRP, this routine walks the stack, and invokes all completion routines that have been registered with IRP. Therefore, if IRP gets completed synchronously by a lower driver, your completion routine will get invoked *before*
your call to IoCallDriver() even returns. Therefore, telling you that IRP has been completed
synchronously opens a door to optimizations in your code. For example, you can avoid an unnecessary call to KeSetEvent() ( access to all dispatcher objects in the system is protected by a single spinlock, so that an unnecessary call to KeSetEvent() is not as harmless as it seems to be at the first glance -if you do it on regular basis your give a significant overhead to the overall OS performance). This is what PendingReturned* flag is for.

This bit gets copied by IoCompleteRequest() to IRP from a current stack location before a completion routine gets invoked. How does it get there?? This is what IoMarkIrpPending() call in a completion routine is for - by calling this routine you tell IoCompleteRequest() to copy the bit from your stack location to the one of an *upper*driver after your completion routine returns. This is why you are going to crash if you call IoMarkIrpPending() in a completion routine but no more stack locations are left…

Anton Bassov

Independent of irp processing, what abstraction is KMDF not providing that you need to process a pnp start irp? Or any pnp irp for that matter?

thx
d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Martin Harvey
Sent: Monday, January 14, 2008 8:01 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] WDF filtering PnP IRP handling: What have I got wrong?

Martin Harvey wrote:

Hi folks,

I’ve probably made a silly error here, but I can’t work out what I’ve
done wrong. I get an error via driver verifier, but clearly WDF is
making my memory for the details of PnP Irp handling rather vague…

Doh! Idiot!

From MSDN:

If a driver sets an /IoCompletion/
http: routine for an
IRP and then passes the IRP down to a lower driver, the /IoCompletion/
routine should check the IRP->PendingReturned flag. If the flag is
set, the /IoCompletion/ routine must call IoMarkIrpPending with the
IRP. (/IoCompletion/ routines do not return STATUS_PENDING, however. For
more information, see Implementing an /IoCompletion/ Routine
http:.)




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</http:></http:>

Doron Holan wrote:

Independent of irp processing, what abstraction is KMDF not providing that you need to process a pnp start irp? Or any pnp irp for that matter?

Oh, none, except that I want to log the IRP’s in order to make my next
ntdev post … :wink:

MH.

Well, all pnp state changing IRPs are logged to the driver’s log buffer, so !wdflogdump would have given you the same info without any more code ;).

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Martin Harvey
Sent: Monday, January 14, 2008 12:02 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] WDF filtering PnP IRP handling: What have I got wrong?

Doron Holan wrote:

Independent of irp processing, what abstraction is KMDF not providing that you need to process a pnp start irp? Or any pnp irp for that matter?

Oh, none, except that I want to log the IRP’s in order to make my next
ntdev post … :wink:

MH.


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