KMDF completion routine - a couple questions

In KMDF request completion routines …

  1. If I’ve previously reformatted the request (eg in the read/write callback), do I need to reformat the request again in my completion routine before completing the request? From looking at toaster, it appears the answer is ‘no’, but that may only be because they are only reformatting the request to add a completion routine, and not doing any substantial reformatting (eg, replacing buffers). Is it always the case that you don’t need to reformat in the completion routine, or are there certain cases where you need to reformat?

  2. Is there a definitive reference source as to what the “information” needs to be set to when using WdfRequestCompleteWithInformation? Based on looking at sample code and posts here and elsewhere, I’ve ascertained that this needs to be the transfer size for Read/Write requests, but what about various IOCTLs that I might recieve and do nothing with except forward? Do I need to pull out the “information” from my request completion parameters and call WdfRequestCompleteWithInformation using *that* information?

WRT #2 above it seems as if the answer is “you need to return information appropriate to the request and for the drivers above you”, but where is this documented? (Especically since you never will know who’s above you and what they will be expecting to see).

Thanks!

-ml

xxxxx@azathoth.net wrote:

  1. If I’ve previously reformatted the request (eg in the read/write callback), do I need to reformat the request again in my completion routine before completing the request? From looking at toaster, it appears the answer is ‘no’, but that may only be because they are only reformatting the request to add a completion routine, and not doing any substantial reformatting (eg, replacing buffers). Is it always the case that you don’t need to reformat in the completion routine, or are there certain cases where you need to reformat?

I mentioned earlier in the week that a WDFREQUEST really manages two
pieces of state: the IRP you received from above, and the IRP it is
preparing to send below. Reformatting only affects the IRPs that you
are sending below. The original IRP is still there, so you can complete
it as is.

I assume you’ve copied the data back to the original buffers.

  1. Is there a definitive reference source as to what the “information” needs to be set to when using WdfRequestCompleteWithInformation? Based on looking at sample code and posts here and elsewhere, I’ve ascertained that this needs to be the transfer size for Read/Write requests, but what about various IOCTLs that I might recieve and do nothing with except forward? Do I need to pull out the “information” from my request completion parameters and call WdfRequestCompleteWithInformation using *that* information?

When you call WdfRequestComplete, the Information value in the status
block is left alone. If a previous driver set it, the value will
propagate on up. The Information value is global to the IRP, not local
to a stack location.


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

On Fri, Feb 12, 2016 at 12:47:04PM -0800, Tim Roberts wrote:

xxxxx@azathoth.net wrote:
> 1. If I’ve previously reformatted the request (eg in the read/write callback), do I need to reformat the request again in my completion routine before completing the request? From looking at toaster, it appears the answer is ‘no’, but that may only be because they are only reformatting the request to add a completion routine, and not doing any substantial reformatting (eg, replacing buffers). Is it always the case that you don’t need to reformat in the completion routine, or are there certain cases where you need to reformat?

I mentioned earlier in the week that a WDFREQUEST really manages two
pieces of state: the IRP you received from above, and the IRP it is
preparing to send below. Reformatting only affects the IRPs that you
are sending below. The original IRP is still there, so you can complete
it as is.

Yep, just wanted to make sure this applies to the completion path as well,
which you just confirmed :slight_smile:

I assume you’ve copied the data back to the original buffers.

I want to make sure we are talking about the same thing.
This is a driver that does some simple modification of data in the write
path and corresponding un-modification of data when subsequently read.

Write path:
create new wdfmemory
copy original request buffer
modify new buffer
reformat request
send request

Write completion path:
free wdfmemory allocated earlier
complete request

Read path:
reformat request (to add completion routine)
send request

Read completion path:
un-modify buffer in place
complete request

This seems to work, but the reason I’m asking the two questions in this thread
is to make sure I won’t get burned by this approach :slight_smile:

> 2. Is there a definitive reference source as to what the “information” needs to be set to when using WdfRequestCompleteWithInformation? Based on looking at sample code and posts here and elsewhere, I’ve ascertained that this needs to be the transfer size for Read/Write requests, but what about various IOCTLs that I might recieve and do nothing with except forward? Do I need to pull out the “information” from my request completion parameters and call WdfRequestCompleteWithInformation using *that* information?

When you call WdfRequestComplete, the Information value in the status
block is left alone. If a previous driver set it, the value will
propagate on up. The Information value is global to the IRP, not local
to a stack location.

Ok this makes sense. In the context of question #1 above, if I am reformatting the request,
does the information value still propagate, or do I need to manually copy? (wouldn’t this
be a different IRP?) I would guess that I would need to copy this as the system is unlikely
to be able to ascertain that these two IRPs are related?

Thanks for the help.

-ml


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


NTDEV is sponsored by OSR

Visit the list online at: http:
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

Mike Larkin wrote:

I want to make sure we are talking about the same thing.
This is a driver that does some simple modification of data in the write
path and corresponding un-modification of data when subsequently read.

Write path:
create new wdfmemory
copy original request buffer
modify new buffer
reformat request
send request

Write completion path:
free wdfmemory allocated earlier
complete request

Read path:
reformat request (to add completion routine)
send request

Read completion path:
un-modify buffer in place
complete request

This seems to work, but the reason I’m asking the two questions in this thread
is to make sure I won’t get burned by this approach :slight_smile:

So, in the read path, you are returning the original buffer from the
write path? Yes, that’s different from what I’m talking about.

Ok this makes sense. In the context of question #1 above, if I am reformatting the request,
does the information value still propagate, or do I need to manually copy? (wouldn’t this
be a different IRP?) I would guess that I would need to copy this as the system is unlikely
to be able to ascertain that these two IRPs are related?

WDF is a great thing, but the abstraction causes us to lose track of the
WDM basis behind it. An IRP consists of two sections: a global section,
and a set of “stack locations”, one for each driver. Reformatting the
request just sets up the next IRP stack location. It’s still the same
IRP. The IoStatus block is in the global part, so as soon as one
driver sets it, it stays until someone else changes it (usually, only
the bottom level drivers sets Information).


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

Thank Gxd.

Unless you’re *very* good with KMDF, or you’re doing something complicated, it’s best to forget everything you ever knew about WDM and IRPs and treat WDF as an entirely different thing. Like writing drivers for a whole different system.

Mapping things back and forth in your head will cause you to spend MUCH time on GitHub trying to determine what’s going on… not to mention, your driver will look like a WDM driver written in WDF.

Just a word to the wise…

Peter
OSR
@OSRDrivers

>WdfRequestCompleteWithInformation?

== Irp->IoStatus.Information?

be the transfer size for Read/Write requests, but what about various IOCTLs that I might recieve

Filled output buffer size?


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

Thanks everyone for the feedback!

-ml

A quick followup -

I was originally trying to commandeer the incoming buffer and modify its content (for both writes and reads, reads in the completion routine). For whatever reason, this approach (reformatting the request with new wdfmemory/etc, and restoring the original buffer later) gave odd behavior (applications seeing inconsistent/incoherent data, various verifier asserts, etc).

I moved to a model where I create (/reuse) a new request/wdfmemory on each incoming request, copy the data (either in the callback or in the completion routine, depending on the situation), and use my own request instead of the original one. That seems to have resolved all the odd behavior.

It may be the case that I was doing something wrong in the first approach, but the second approach is pretty simple to read (and works), so for now, this is what I’m going with.

Thanks for the feedback/help along the way.

-ml