stupid completion question

Dear all:

May I ask that:

NTSTATUS
DispatchRoutine_1(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
//
// You are not setting a completion routine, so just skip the stack
// location because it provides better performance.
//
IoSkipCurrentIrpStackLocation (Irp);
return IoCallDriver(TopOfDeviceStack, Irp);
}

In this case,
does it means if we are not the lowest layer driver and have no completion routine, we don’t need to call IoCompleteRequest ?
if it does not call IoCompleteRequest, how can I/O manager know the irp is completed ?
Does every layer driver must notify I/O manager the irp is completed ?

Why does IoCompleteRequest be called sometimes in dispath function and sometimes in completion routine ?

Best Reagrds,
Alan

In your example some driver below you will complete the request. Each
individual IO request can only be completed once. An individual Io Request
Packet (IRP) may be re-used, and thus may be passed to IoCompleteRequest
several times.

Where in a code path (dispatch routine, dpc routine, completion handler) an
IRP is passed to IoCompleteRequest depends on the design of your driver.
Lowest level drivers must complete requests, other drivers may also complete
requests.

As a simple example of when a completion handler is used to complete an IRP,
consider a class (intermediate) driver, such as the disk driver, that must
break a single request IRP into more than one individual IRPs. It could
queue the original request IRP in its dispatch routine, send the new IRPs
down to an HBA driver, and in its completion handler for those IRPs track
when all of these requests have been completed. Once all the requests are
complete, the completion handler detecting this condition would then unqueue
and complete the original request IRP.


From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Alan Kung
Sent: Thursday, July 01, 2004 11:49 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] stupid completion question

Dear all:

May I ask that:

NTSTATUS
DispatchRoutine_1(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
//
// You are not setting a completion routine, so just skip the stack
// location because it provides better performance.
//
IoSkipCurrentIrpStackLocation (Irp);
return IoCallDriver(TopOfDeviceStack, Irp);
}

In this case,
does it means if we are not the lowest layer driver and have no completion
routine, we don't need to call IoCompleteRequest ?
if it does not call IoCompleteRequest, how can I/O manager know the irp is
completed ?
Does every layer driver must notify I/O manager the irp is completed ?

Why does IoCompleteRequest be called sometimes in dispath function and
sometimes in completion routine ?

Best Reagrds,
Alan

Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@hollistech.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

>does it means if we are not the lowest layer driver and have no completion
routine, we don’t

need to call IoCompleteRequest ?
if it does not call IoCompleteRequest, how can I/O manager know the irp is
completed ?

The lower driver will do this. Your driver will never see this IRP again.

Does every layer driver must notify I/O manager the irp is completed ?

No. Usually only the lowest driver does this. But, if you have returned
STATUS_MORE_PROCESSING_REQUIRED from the completion routine, and the IRP is not
created by you but came from above - then you must call IoCompleteRequest too.

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

Maybe he should think of an IRP as a very, very hot rivet. When you have
the IRP in your hand it will be hot. When you pass it off with IoCallDriver
or maybe the PO version for power IRPs, it is no longer yours. You hand is
then cold but you can put the rivet into the metal beams. Just as with a
rivet you can’t try and tough the IRP in any way after you have passed it
off. IoCompleteRequest is the other passoff method where the IRP is passed
to the IoManager and the one who made the call cannot reference it after
that point.

A common error beginners make is to call IoCompleteRequest in their dispatch
routine and then try to access the IoStatus structure to return the status
from it. Bad idea that will cause intermittent blue screens and other
wonderful problems, usually after it is on the customer’s computer.

I hope the questioner will take a beginning device driver class where these
concepts are repeated several times.

“Maxim S. Shatskih” wrote in message
news:xxxxx@ntdev…
> >does it means if we are not the lowest layer driver and have no
completion
> routine, we don’t
> >need to call IoCompleteRequest ?
> >if it does not call IoCompleteRequest, how can I/O manager know the irp
is
> completed ?
>
> The lower driver will do this. Your driver will never see this IRP again.
>
> >Does every layer driver must notify I/O manager the irp is completed ?
>
> No. Usually only the lowest driver does this. But, if you have returned
> STATUS_MORE_PROCESSING_REQUIRED from the completion routine, and the IRP
is not
> created by you but came from above - then you must call IoCompleteRequest
too.
>
> Maxim Shatskih, Windows DDK MVP
> StorageCraft Corporation
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>

Dear Mark Roddy

Thank you for the help.

in the following code example,
May I ask

does it re-use the irp ? Why the completion routine can only return STATUS_MORE_PROCESSING_REQUIRED ?
Does the CompletionRoutine_2 be finished before it call IoCompleteRequest ?

NTSTATUS
DispatchRoutine_2(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KEVENT event;
NTSTATUS status;

KeInitializeEvent(&event, NotificationEvent, FALSE);

//
// You are setting completion routine, so you must copy
// current stack location to the next. You cannot skip a location
// here.
//
IoCopyCurrentIrpStackLocationToNext(Irp);

IoSetCompletionRoutine(Irp,
CompletionRoutine_2,
&event,
TRUE,
TRUE,
TRUE
);

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;
}

// <---- Do your own work here.

//
// Because you stopped the completion of the IRP in the CompletionRoutine
// by returing STATUS_MORE_PROCESSING_REQUIRED, you must call
// IoCompleteRequest here.
//
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;

}
NTSTATUS
CompletionRoutine_2(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
if (Irp->PendingReturned == TRUE) {
//
// You will set the event only if the lower driver has returned
// STATUS_PENDING earlier. This optimization removes the need to
// call KeSetEvent unnecessarily and improves performance because the
// system does not have to acquire an internal lock.
//
KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
}
// This is the only status you can return.
return STATUS_MORE_PROCESSING_REQUIRED;
}

Best Regards,

This case is the “dispatch side post processing case”. The IRP is not being
re-used, instead your driver’s completion handler is interrupting the
completion process, preventing the OS from completing the IO request. The
completion handler signals a waiting thread (represented by your dispatch
routine) and that waiting thread process the results of the IO request and
then restarts the completion process that was interrupted by the completion
handler. The IRP in question is not being reused for another IO request as
the original IO request has not been fully processed. Having interrupted the
original IRP completion, the dispatch side processing must complete this IRP
a second time. Note that this sort of processing can be repeated by every
driver in a device stack.

See the following:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;320275 and
http://www.microsoft.com/whdc/driver/kernel/IRPs.mspx


From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Alan Kung
Sent: Sunday, July 04, 2004 10:18 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] stupid completion question

Dear Mark Roddy

Thank you for the help.

in the following code example,
May I ask

does it re-use the irp ? Why the completion routine
can only return STATUS_MORE_PROCESSING_REQUIRED ?
Does the CompletionRoutine_2 be finished before it call
IoCompleteRequest ?

NTSTATUS
DispatchRoutine_2(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KEVENT event;
NTSTATUS status;

KeInitializeEvent(&event, NotificationEvent, FALSE);

//
// You are setting completion routine, so you must copy
// current stack location to the next. You cannot skip a
location
// here.
//
IoCopyCurrentIrpStackLocationToNext(Irp);

IoSetCompletionRoutine(Irp,
CompletionRoutine_2,
&event,
TRUE,
TRUE,
TRUE
);

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;
}

// <---- Do your own work here.

//
// Because you stopped the completion of the IRP in the
CompletionRoutine
// by returing STATUS_MORE_PROCESSING_REQUIRED, you must call
// IoCompleteRequest here.
//
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;

}
NTSTATUS
CompletionRoutine_2(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
if (Irp->PendingReturned == TRUE) {
//
// You will set the event only if the lower driver has returned
// STATUS_PENDING earlier. This optimization removes the need to
// call KeSetEvent unnecessarily and improves performance
because the
// system does not have to acquire an internal lock.
//
KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
}
// This is the only status you can return.
return STATUS_MORE_PROCESSING_REQUIRED;
}

Best Regards,


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as: xxxxx@hollistech.com
To unsubscribe send a blank email to xxxxx@lists.osr.com