dispatch handler return status inconsistent with IoStatus.Status

after learning how to use driver verifier this week, i turned it on for some testing with my fs filter driver and up pops the message:

An IRP dispatch handler has returned a status that is inconsistent with the Irp’s IoStatus.Status field

the message makes perfect sense, but i don’t know how to fix it. what i’m trying to do, is in my completion routine, i want to change the ntstatus from STATUS_SUCCESS to an error status.

the comp routine is more or less ends with:

if( Irp->IoStatus.Status == STATUS_SUCCESS ) {
Irp->IoStatus.Status = STATUS_NO_SUCH_FILE;
Irp->IoStatus.Information = 0;
}
return(Irp->IoStatus.Status)

and the dispatch routine does:
IoSetCompletionRoutine(Irp,TheCompletionRoutine,…);
return(IoCallDriver(NextLowerDevice,Irp));

if it matters, I’m messing with the results of IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY.

how do i accomplish my goal of changing the status?

mike

There are a few things wrong here… I’m not certain what verifier is complaining about, specifically:

  1. In terms of your completion routine: You do not return the IRP’s status from your COMPLETION routine. You return STATUS_SUCCESS to tell the I/O Manager that you’re done with the IRP and to continue his completion processing, or you return STATUS_MORE_PROCESSING_REQUIRED to tell the I/O Manager that you want to KEEP the IRP and he should subsequently NOT continue his completion processing (and leave the IRP with you).

Now, in terms of actual implementation, the I/O Manager only looks to see if the returned value is STATUS_MORE_PROCESSING_REQUIRED or not… so this isn’t likely to be causing the verifier error. But your code IS wrong as shown.

  1. In terms of your dispatch routine: Consider what happens when the driver below you returns STATUS_PENDING. This is probably what’s happening. If you just do:

return( IoCallDriver(…) );

Then if HE returns STATUS_PENDING, then YOU’RE returning STATUS_PENDING to you caller. If you do this, you need to set the Pending bit in the IRP. To do this, you propagate the pending bit in your completion routine, like so:

if (Irp->PendingReturned)
IoMarkIrpPending(Irp);

Start there.

May I humbly recommend you consider taking a seminar on developing Windows drivers? And starting with a file system filter is an AWFULLY tough way to begin, by the way.

Peter
OSR

darn computers! it apparently didn’t like my first response, so i’ll try again…

In fact, I did attend the OSR internals course just last week and learned a lot. It was apparent early on that a fs filter was a tough assignment to start with.

I was initially returning STATUS_SUCCESS and changed it to see if it would make verifier happy, which it didn’t. I’ll change that back. In the comp routine, I am propagating the pending bit as you say (and after the class understand *why* we need to do it that way).

I don’t pend any requests in my dispatch routine, just pass them along to the lower driver and look at the response in the comp routine.

Bravo on taking the seminar. AND, you’ve got enough energy left that you’re already diving into your file system filter? Good for you!

Well… hmmm. It’s architecturally incorrect to complete an IRP and return a status different from that with which you completed the IRP. In other words, ARCHITECTURALLY speaking, you’re NOT supposed to do the following:

Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, 0);

Return STATUS_SUCCESS;

I mean… there’s no reason that it won’t WORK as far as the I/O Manager is concerned, but it’s not “right.”

I wonder if this is what Driver Verifier is complaining about. You’re effectively doing exactly this, right?

It COULD be (guessing here) that to make Driver Verifier happy you need to reclaim the IRP in the Dispatch Routine, change its status, and call IoCompleteRequest on it?

Sorry, don’t have the source code in front of me to allow me to check right now… but that might be something for you to try.

P

This problem has been nagging me all weekend, so I looked through the source a bit and came up with a theory. See if this makes sense…

The lower driver (I think it’s sr in my system), handles the request, plays nicely and sets IoStatus.Status = STATUS_SUCCESS and returns STATUS_SUCCESS. My comp routine gets called since somebody lower than me did IoCompleteRequest then I set IoStatus.Status = STATUS_BLAH and return STATUS_SUCCESS. Eventually, control is returned to my dispatch routine which did return(IoCallDriver(…)). This would seem to cause the condition that verifier is complaining about, right? And this would only happen if the lower driver completed the IRP synchronously, I believe.

Assuming this scenario is what’s happening, here’s how I would solve the problem:
DispatchRoutine()
{
LONG FinalStatus;
IoSetCompletionRoutine(Irp, CompRoutine, &FinalStatus)
status = IoCallDriver(TheNextGuy, Irp)
if( status != STATUS_PENDING )
status = FinalStatus; /* must have been completed synchronously, right? */
return( status );
}

CompRoutine()
{
LONG *FinalStatus = Context;
if( i_feel_like_it && NT_SUCCESS( Irp->IoStatus.Status ))
{
*FinalStatus = Irp->IoStatus.Status = STATUS_BLAH;
Irp->IoStatus.Information = 0;
}
else
*FinalStatus = Irp->IoStatus.Status;
return( STATUS_SUCCESS );
}

I’d like to skip the whole FinalStatus thingy and do:
status = IoCallDriver()
if( status != STATUS_PENDING )
status = Irp->IoStatus.Status;

But I think that breaks the rules since I don’t own the IRP anymore, or do I for synchronous calls?

Thanks for your assistance.
Mike

>IoSetCompletionRoutine(Irp, CompRoutine, &FinalStatus)

status = IoCallDriver(TheNextGuy, Irp)
if( status != STATUS_PENDING )
status = FinalStatus; /* must have been completed synchronously, right?
*/
return( status );

This is pretty clever…I wanted to believe that it wouldn’t work, but I
can’t think of a case where it wouldn’t give the desired result.

But I think that breaks the rules since I don’t own the IRP anymore, or do
I for synchronous calls?

Right, that breaks the rules because you don’t own the IRP anymore.

What IRPs are you doing this with? While your first method should work, the
only way that I can think of solving this in an architecturally defined way
would be to always pend the IRP that you might change the status for in the
completion routine. So:

DispatchRoutine()
{
IoMarkIrpPending()
IoSetCompletionRoutine(Irp, CompRoutine, &FinalStatus)
(VOID)IoCallDriver(TheNextGuy, Irp)
return STATUS_PENDING;
}

CompRoutine()
{
if( i_feel_like_it && NT_SUCCESS( Irp->IoStatus.Status ))
{
Irp->IoStatus.Status = STATUS_BLAH;
Irp->IoStatus.Information = 0;
}
return( STATUS_SUCCESS );
}

The only problem with this that it isn’t appropriate for the class of IRPs
for which STATUS_PENDING means success (such as
IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY_CHANGE_NOTIFICATION).

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

I’d like to solve the problem the “right” way. It looks like the small change to the dispatch routine would be the correct way. Would this have an adverse affect on performance?

I’m handling IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY. How would I find out if returning STATUS_PENDING would work for this IRP?

Mike

You can return pending for IRP_MN_QUERY_DIRECTORY, it’s just the change
notification minor function that is an issue (pending means success in that
case).

I don’t generally think of returning pending as being a performance problem.
It does have overhead over the synchronous completion case, but I usually
look elsewhere when it comes time for perf improvements (timing the
difference would make an interesting experiment though if anyone hasn’t done
it yet).

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntfsd…

I’d like to solve the problem the “right” way. It looks like the small
change to the dispatch routine would be the correct way. Would this have an
adverse affect on performance?

I’m handling IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY. How would I
find out if returning STATUS_PENDING would work for this IRP?

Mike

So I think I’m down to one last question now. What happens when the lower driver completes the request and THEN my dispatch routine returns STATUS_PENDING? I recall something like that being discussed in class last week. I think the answer is that this is not a problem since the I/O manager already knows the IRP is completed and basically ignores the STATUS_PENDING. Is that right?

Mike

Yes, this case “just works.” It’s part of the magic of I/O completion.

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntfsd…

So I think I’m down to one last question now. What happens when the lower
driver completes the request and THEN my dispatch routine returns
STATUS_PENDING? I recall something like that being discussed in class last
week. I think the answer is that this is not a problem since the I/O manager
already knows the IRP is completed and basically ignores the STATUS_PENDING.
Is that right?

Mike