Scenario 9 - STATUS_MORE_PROCESSING_REQUIRED and Complete in the Dispatch Routine

Hi

As you know there are 8 Irp Handling scenarios in WDM book. I have one more
that i couldn’t figure out what gonna happen next.

A-) In Intermediate Driver:

Dispatch Routine:
//////////////////////////
KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,CatchIrpRoutine,&event,TRUE,TRUE,TRUE);
status = IoCallDriver(DeviceObject, Irp);

if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(&event,Executive,KernelMode,FALSE,NULL);
ASSERT(NT_SUCCESS(status));
status = Irp->IoStatus.Status;
}
return status;
///////////////////////

Completion Routine:
////////////////////////
NTSTATUS CatchIrpRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN
PKEVENT Event)
{
if (Irp->PendingReturned) {
KeSetEvent( Event, IO_NO_INCREMENT, FALSE );
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
/////////////////////

B-)Lowest Level Driver:

It doesn’t make device operation, just complete it and return in Dispatch
routine:

Irp->IoStatus.Status = STATUS_XXX; //1
Irp->IoStatus.Information = YYY; // 2
IoCompleteRequest(Irp, IO_NO_INCREMENT);// 3
return STATUS_XXX; // 4

1-) When 3. line is executed, IoCompleteRequest() will call Completion
Routines that previously registered, before returning STATUS_XXX
2-) After calling IoCompleteRequest(), In that step, CatchIrpRoutine starts
to execute and and return STATUS_MORE_PROCESSING_REQUIRED
3-) STATUS_MORE_PROCESSING_REQUIRED means stops the upward completion of the
IRP and leaves the IRP stack pointer at its current location

4-) So, here, in step 4 , after returning STATUS_MORE_PROCESSING_REQUIRED,
Is
a. “return STATUS_XXX;” executed, or
b. Intermediate Drivers Dispatch Routine executed?

5-) (I have no idea??)

Can you please help me to figure out what happens in step 4 and 5?
Thank you…

Since CatchIrpRoutine returns STATUS_MORE_PROCESSING_REQUIRED you need to complete the Irp in your Intermediate Driver Dispatch routine. You are not doing that. I would read the Irps.doc at
http://www.microsoft.com/whdc/driver/kernel/IRPs.mspx. You can see an example of this in Scenario 2: Forward and Wait at:
http://support.microsoft.com/kb/320275.

OK.
We can change it.

status = IoCallDriver(TopOfDeviceStack, Irp);

if (status == STATUS_PENDING) {

KeWaitForSingleObject(&event,
Executive, // WaitReason
KernelMode, // must be Kernelmode to
prevent the stack getting paged out
FALSE,
NULL // indefinite wait
);
status = Irp->IoStatus.Status;
}
//Line ***

IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;

  • So here, It calls IoCallDriver() and returns “status”.
  • But lowest level driver which it calls, calls
    IoCompleteRequest(Irp, IO_NO_INCREMENT); before return STATUS_XXX;
  • I\O Manager starts to execute Completion Routines before returning
    IoCallDriver(). Right?
  • And even IoCallDriver hasn’t returned yet, Completion Routine returns
    STATUS_MORE_PROCESSING_REQUIRED and go to “Line ***”, so this code is never
    executed:

if (status == STATUS_PENDING) {if (status == STATUS_PENDING)

Isn’t that weird?

2008/10/7

> Since CatchIrpRoutine returns STATUS_MORE_PROCESSING_REQUIRED you need to
> complete the Irp in your Intermediate Driver Dispatch routine. You are not
> doing that. I would read the Irps.doc at
> http://www.microsoft.com/whdc/driver/kernel/IRPs.mspx. You can see an
> example of this in Scenario 2: Forward and Wait at:
> http://support.microsoft.com/kb/320275.
>
> —
> 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
>

> And even IoCallDriver hasn’t returned yet, Completion Routine returns >STATUS_MORE_PROCESSING_REQUIRED and go to “Line ***”, so this code is never executed:

By returning STATUS_MORE_PROCESSING_REQUIRED from a completion routine you tell IOCompleteRequest to return immediately, without invoking higher-layered driver’s completion routines.
Therefore, if you return STATUS_MORE_PROCESSING_REQUIRED , your Dispatch routine should call IoCompleteRequest() with a given IRP so that all completion routines that higher higher-layered driver’s completion routines get invoked. However, this status does not get propagated to the higher drivers - what
they are going to receive from IoCallDriver() is the status that lower driver’s Dispatch routine returns, for understandable reasons (look at the lower driver’s code that you have presented yourself and you will realize why it happens). Therefore, if lower driver returns STATUS_PENDING, your block will still get executed- even if your completion routine returns STATUS_MORE_PROCESSING_REQUIRED…

Anton Bassov

Thank you,

In WDM book:
“(…)IoComplete?Request stops dead in its tracks and returns to its caller.
The IRP will then be in a sort of limbo state”
Limbo state?

  • IoComplete?Request() returns to its caller so caller(lowest driver) can
    return status to higher driver. So “status = IoCallDriver(DeviceObject,
    Irp)” is executed and status is assigned.

  • But also Completion Routine returns STATUS_MORE_PROCESSING_REQUIRE, so
    higher level drivers dispatch routine gets control.

There is a conflict here. Lowest driver must return before higher level
drivers dispatch routine gets control. Right?
So is this what “limbo state” is?

2008/10/7

> > And even IoCallDriver hasn’t returned yet, Completion Routine returns
> >STATUS_MORE_PROCESSING_REQUIRED and go to “Line ***”, so this code is never
> executed:
>
>
> By returning STATUS_MORE_PROCESSING_REQUIRED from a completion routine you
> tell IOCompleteRequest to return immediately, without invoking
> higher-layered driver’s completion routines.
> Therefore, if you return STATUS_MORE_PROCESSING_REQUIRED , your Dispatch
> routine should call IoCompleteRequest() with a given IRP so that all
> completion routines that higher higher-layered driver’s completion routines
> get invoked. However, this status does not get propagated to the higher
> drivers - what
> they are going to receive from IoCallDriver() is the status that lower
> driver’s Dispatch routine returns, for understandable reasons (look at the
> lower driver’s code that you have presented yourself and you will realize
> why it happens). Therefore, if lower driver returns STATUS_PENDING, your
> block will still get executed- even if your completion routine returns
> STATUS_MORE_PROCESSING_REQUIRED…
>
>
> Anton Bassov
>
>
>
> —
> 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
>

serimc wrote:

Thank you,

In WDM book:
“(…)IoComplete­Request stops dead in its tracks and returns to its
caller. The IRP will then be in a sort of limbo state”
Limbo state?

Yes. Not destroyed, not completed. The IRP still lives, but no one
will ever touch it again.

  • IoComplete­Request() returns to its caller so caller(lowest driver)
    can return status to higher driver. So “status =
    IoCallDriver(DeviceObject, Irp)” is executed and status is assigned.

  • But also Completion Routine returns STATUS_MORE_PROCESSING_REQUIRE,
    so higher level drivers dispatch routine gets control.

No, that sentence is false. If the completion routine returns
STATUS_MORE_PROCESSING_REQUIRED, then no more completion routines will
get called. Processing stops, the IRP will not be completed, and the
higher-level IoCallDriver will not return. The IRP will continue to
live until someone completes it properly – until “more processing”
happens. If no one realizes that it needs to be completed, the IRP will
live on forever, ignored. In limbo.

There is a conflict here. Lowest driver must return before higher
level drivers dispatch routine gets control. Right?
So is this what “limbo state” is?

If the completion routine returns STATUS_MORE_PROCESSING_REQUIRED,
IoCallDriver won’t return.


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

Tim’s right, of course.

The entire world of IoCompleteRequest and completion routines is rather well described (in an ELEVEN year old article… how time flies, huh??) at:

http://www.osronline.com/article.cfm?id=83

Also some info at:

http://www.osronline.com/article.cfm?article=214

You also might find some helpful code (NOT THE OBSERVATIONS IN THE THREAD but the CODE) shown at:

http://www.osronline.com/showThread.cfm?link=111116#T44

(which you will need to format to be able to read properly). Again, JUST pay attention to the code shown in the item cited above… NOT the observations about it, many of which are erroneous as I recall… and I’m not going back to read it to look – Living through it the first time was annoying enough).

Peter
OSR

Tim,

If the completion routine returns STATUS_MORE_PROCESSING_REQUIRED,
then no more completion routines will get called. Processing stops, the IRP will not be completed,
and the higher-level IoCallDriver will not return.

The very last statement in the above sentence is plainly wrong. IOCallDriver() always returns, and it happens right after lowest-level Dispatch routine returns control - it has nothing to do with IoCompleteRequest()'s behavior. Apparently, what you wanted to say here is "higher-level driver will not have an access to IRP after IoCallDriver() returns control until its completion routine gets invoked, i.e. a driver that had earlier returned STATUS_MORE_PROCESSING_REQUIRED calls IoCompleteRequest() once again ", right?

Anton Bassov

xxxxx@hotmail.com wrote:

Tim,

> If the completion routine returns STATUS_MORE_PROCESSING_REQUIRED,
> then no more completion routines will get called. Processing stops, the IRP will not be completed,
> and the higher-level IoCallDriver will not return.
>

The very last statement in the above sentence is plainly wrong. IOCallDriver() always returns, and it happens right after lowest-level Dispatch routine returns control - it has nothing to do with IoCompleteRequest()'s behavior. Apparently, what you wanted to say here is "higher-level driver will not have an access to IRP after IoCallDriver() returns control until its completion routine gets invoked, i.e. a driver that had earlier returned STATUS_MORE_PROCESSING_REQUIRED calls IoCompleteRequest() once again ", right?

Yes, you’re right, what I said is not correct. Presumably, IoCallDriver
will have already returned with a STATUS_PENDING in this case, or we
wouldn’t have gotten to this point. The key is that the higher-level
driver will never see the IRP complete. It’s completion won’t be
called, or its completion event won’t be set.


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

Dear anton bassov, you said :
“IOCallDriver() always returns, and it happens right after lowest-level
Dispatch routine returns control”

Please follow this;

  • status = IoCallDriver(DeviceObject, Irp); line is executed in higher level
    driver so it is waiting to return Dispatch Routine of lowest driver.

  • Lowest Driver will not return Pending state, it will call
    “IoCompleteRequest(Irp, IO_NO_INCREMENT);” before “return STATUS_XXX;”

  • While IoCallDriver() is waiting to return, I\O Manager will call
    completition return of Higher Driver.

  • Higher Driver’s completion Routine will call
    STATUS_MORE_PROCESSING_REQUIRED, and now what will happen?

I am just asking about what will happen next? Because;

At that time, although IoCallDriver hasn’t returned yet, Completition
routine return to higher level driver’s Dispatch return.

Now Which line of code will be executed.

1-) In lowest driver, IoCompleteRequest() finish and “return STATUS_XXX;”
line will be executed so that means IoCallDriver() returns and, higher
driver gets control

or

2-) As shown here, IoCallDriver never returns and IoCompleteRequest() will
be executed in “Higher Driver”

status = IoCallDriver(TopOfDeviceStack, Irp);// That line?? or

//Ignore this, Status Pending will not return
if (status == STATUS_PENDING) {

KeWaitForSingleObject(&event,
Executive, // WaitReason

KernelMode, // must be Kernelmode to
prevent the stack getting paged out
FALSE,
NULL // indefinite wait
);

status = Irp->IoStatus.Status;
}

IoCompleteRequest (Irp, IO_NO_INCREMENT);// OR THAT LINE???
return status;

Please just tell me which line of code will be executed after executing
“return STATUS_MORE_PROCESSING_REQUIRED”.
Go back to Lowest Driver?? or Higher Driver Dispatch routine and
IoCAllDriver never returns?? or something else?

Thanks for all answers…

2008/10/8

>
> Tim,
>
> > If the completion routine returns STATUS_MORE_PROCESSING_REQUIRED,
> > then no more completion routines will get called. Processing stops, the
> IRP will not be completed,
> > and the higher-level IoCallDriver will not return.
>
> The very last statement in the above sentence is plainly wrong.
> IOCallDriver() always returns, and it happens right after lowest-level
> Dispatch routine returns control - it has nothing to do with
> IoCompleteRequest()'s behavior. Apparently, what you wanted to say here is
> "higher-level driver will not have an access to IRP after IoCallDriver()
> returns control until its completion routine gets invoked, i.e. a driver
> that had earlier returned STATUS_MORE_PROCESSING_REQUIRED calls
> IoCompleteRequest() once again ", right?
>
> Anton Bassov
>
> —
> 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
>

Dear Tim Roberts, I post a mail just after you. I tried to explain once
again.

You said:“Presumably, IoCallDriver will have already returned with a
STATUS_PENDING”.
But no. The problem is here, if it returns STATUS_PENDING, no problem, But
it doesn’t.

Before returning, calls IoCompleteRequest() so completion routine starts to
execute and then it will return Status_Success, but unfortunately completion
routine returns STATUS_MORE_PROCESSING_REQUIRED and now?? (as i tried to
explain my previous post)

Thanks…

2008/10/8 Tim Roberts

> xxxxx@hotmail.com wrote:
> > Tim,
> >
> >
> >> If the completion routine returns STATUS_MORE_PROCESSING_REQUIRED,
> >> then no more completion routines will get called. Processing stops, the
> IRP will not be completed,
> >> and the higher-level IoCallDriver will not return.
> >>
> >
> > The very last statement in the above sentence is plainly wrong.
> IOCallDriver() always returns, and it happens right after lowest-level
> Dispatch routine returns control - it has nothing to do with
> IoCompleteRequest()'s behavior. Apparently, what you wanted to say here is
> "higher-level driver will not have an access to IRP after IoCallDriver()
> returns control until its completion routine gets invoked, i.e. a driver
> that had earlier returned STATUS_MORE_PROCESSING_REQUIRED calls
> IoCompleteRequest() once again ", right?
> >
>
> Yes, you’re right, what I said is not correct. Presumably, IoCallDriver
> will have already returned with a STATUS_PENDING in this case, or we
> wouldn’t have gotten to this point. The key is that the higher-level
> driver will never see the IRP complete. It’s completion won’t be
> called, or its completion event won’t be set.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> 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
>

> 1-) In lowest driver, IoCompleteRequest() finish and “return STATUS_XXX;” line

will be executed so that means IoCallDriver() returns and, higher driver gets control

This is exactly what is going to happen. However, it will be unable to access IRP until its completion routine gets invoked, and this may happen only when a driver that had earlier returned STATUS_MORE_PROCESSING_REQUIRED calls IoCompleteRequest() once again. In your particular case, once it is your driver is the one who has returned STATUS_MORE_PROCESSING_REQUIRED it will be able to access IRP right after IoCallDriver() returns control (because, judging from your example,
we are speaking about synchronous completion here - the lower driver calls IoCompleteRequest() right in its Dispatch routine, so that IoCallDriver() returns AFTER a completion routine has been already invoked)…

Anton Bassov

In the end the dispatch routine can only do one of two things:

a) Return the same status the IRP has ALREADY been completed with ?or-

b) Return STATUS_PENDING

If any driver returns STATUS_MORE_PROCESSING_REQUIRED from its completion routine but doesn?t complete the IRP before it returns STATUS_SUCCESS from its dispatch routine then that driver has a bug.

If your driver returns SMPR from its completion routine it can either complete the request before the dispatch routine returns & return a non-pending status from the dispatch routine (the same value the IRP was completed with) or it can hold onto the IRP but in that case the dispatch routine MUST return STATUS_PENDING because the IRP has not yet been completed.

The situation you describe in your last mail sounds like a bug to me since you don?t mention anyone completing the IRP after the CR returned SMPR.

-p

From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of serimc
Sent: Tuesday, October 07, 2008 6:01 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Scenario 9 - STATUS_MORE_PROCESSING_REQUIRED and Complete in the Dispatch Routine

Dear Tim Roberts, I post a mail just after you. I tried to explain once again.

You said:“Presumably, IoCallDriver will have already returned with a STATUS_PENDING”.
But no. The problem is here, if it returns STATUS_PENDING, no problem, But it doesn’t.

Before returning, calls IoCompleteRequest() so completion routine starts to execute and then it will return Status_Success, but unfortunately completion routine returns STATUS_MORE_PROCESSING_REQUIRED and now?? (as i tried to explain my previous post)

Thanks…

2008/10/8 Tim Roberts >
xxxxx@hotmail.commailto:xxxxx wrote:
> Tim,
>
>
>> If the completion routine returns STATUS_MORE_PROCESSING_REQUIRED,
>> then no more completion routines will get called. Processing stops, the IRP will not be completed,
>> and the higher-level IoCallDriver will not return.
>>
>
> The very last statement in the above sentence is plainly wrong. IOCallDriver() always returns, and it happens right after lowest-level Dispatch routine returns control - it has nothing to do with IoCompleteRequest()'s behavior. Apparently, what you wanted to say here is "higher-level driver will not have an access to IRP after IoCallDriver() returns control until its completion routine gets invoked, i.e. a driver that had earlier returned STATUS_MORE_PROCESSING_REQUIRED calls IoCompleteRequest() once again ", right?
>
Yes, you’re right, what I said is not correct. Presumably, IoCallDriver
will have already returned with a STATUS_PENDING in this case, or we
wouldn’t have gotten to this point. The key is that the higher-level
driver will never see the IRP complete. It’s completion won’t be
called, or its completion event won’t be set.


Tim Roberts, xxxxx@probo.commailto:xxxxx
Providenza & Boekelheide, Inc.


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

— 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</mailto:xxxxx></mailto:xxxxx>

> Presumably, IoCallDriver will have already returned with a STATUS_PENDING in this case,

or we wouldn’t have gotten to this point.

Well, in fact, it looks like the OP speaks about the synchronous completion here - the excerpt that he has provided calls IoCompleteRequest() right in lower driver’s Dispatch routine. Therefore, if the return status is STATUS_PENDING, the event will be already signaled by the time IoCallDriver() returns - his IF block will get executed, but wait() is not going to block…

Anton Bassov