IRP Completion Rules -- I/O Completion Routine Rules

If we can get broad concensus on these rules (thanks Max), I’ll be MORE than
happy to post them on the web site in a prominent place.

I’ve done some editing on Max’ original rules, limited their scope
somewhat, and added a couple more.

Corrections/suggestions/recommendations appreciated.

Peter
OSR


IRP Completion Rules

  • If a dispatch routine returns STATUS_PENDING, the IRP passed into the
    dispatch routine must be marked pending with IoMarkIrpPending().
  • If an IRP is marked pending with IoMarkIrpPending() in a dispatch routine,
    that dispatch routine must return STATUS_PENDING.
  • If an IRP is to be marked pending, IoMarkIrpPending must be called before
    the IRP is accessible from any context in which it might be completed.
  • If you complete the IRP in the dispatch routine, you must fill
    Irp->IoStatus.Status with the IRP’s completion status (this may NOT be
    STATUS_PENDING), you must fill Irp->IoStatus.Information with the number of
    bytes read or written by the request if the request is being completed with
    a success status (for data transfer operations and IOCTLs), and then you
    must call IoCompleteRequest(). On return from the dispatch routine, you must
    return the same status that you filled into Irp->IoStatus.Status. Note that
    in some cases Irp->IoStatus.Information can hold a pointer.
  • Once you call IoCompleteRequest(), you no longer “own” the IRP, and must
    not refer to any of its contents.
  • Irp->IoStatus.Status must be filled only just before IoCompleteRequest.
    You can use Irp->IoStatus as a temporary storage before this, assuming you
    do not pass the IRP to another driver.
  • Because of special logic in the I/O Manager’s completion handling code,
    drivers can also pass an IRP to another by “return IoCallDriver(.)”. In this
    case, IoMarkIrpPending must not be called.
  • The following sequence is also valid, though slower. It is necessary as a
    workaround for filtering some buggy drivers like NT4’s CDFS:

IoMarkIrpPending(Irp);
(VOID)IoCallDriver(BottomDeviceObject, Irp);
return STATUS_PENDING;

I/O Completion Routines

  • There are only three valid return codes from an I/O Completion Routine:
    STATUS_MORE_PROCESSING_REQUIRED, STATUS_SUCCESS, and
    STATUS_CONTINUE_COMPLETION (which is identical to STATUS_SUCCESS, see
    NTDDK.H)

  • STATUS_MORE_PROCESSING_REQUIRED means that IoCompleteRequest returns to
    its caller
    immediately. No further completion routines are called, and IRP is not
    returned to the I/O Manager.

  • If and only if the completion routine returns STATUS_SUCCESS (or
    STATUS_CONTINUE_COMPLETION) , then it must do the following:

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

  • If your completion routine returns STATUS_MORE_PROCESSING_REQUIRED, your
    dispatch routine for that IRP (if you have one, that is, if you did not
    create the IRP in your driver) must either return STATUS_PENDING or it must
    block until the completion routine has run (for example, waiting on an event
    that is set from within the completion routine).

Looking good, but that STATUS_CONTINUE_COMPLETION must be a part of the XP
DDK for SP1. I can’t find it in the XP or 2000 DDK.

  • Once you call IoCompleteRequest(), you no longer “own” the IRP, and must
    not refer to any of its contents.

I think this needs to be expanded. Too many beginners try the logic of
setting IoStatus, do the IoCompleteRequest(), and then try to return the
IoStatus using the IRP itself. Works much of the time for many drivers, so
they think it is OK to use it every where. If you are using the event and
waiting in the dispatch routine, it may look like it is inefficient and
wasteful to just copy the status out of the IRP into a local just so it can
be returned, but it is mandatory if you want it to work correctly all the
time.

A note on efficiency might mention that this waiting in the dispatch routine
and then doing some post processing should be for short code paths only. It
is clearer and more maintainable to have the dispatch do the preprocessing
and let a dedicated completion routine finish up. The only time this is not
advisable is if the user context needs to be in place for the post
completion logic in your driver. The IoManager will get the user context
restored for final completion processing which is why the marking of the IRP
is needed.

I know you cover this in the OSR courses, but maybe it will be helpful for
new developers to understand how and why much of this works. I don’t think
Microsoft gives us the source to the IoManager so it is hard to understand
some of this stuff. There is also a link to APCs and special kernel APCs
and some of the funny rules we have to follow.

----- Original Message -----
From: “Peter Viscarola”
Newsgroups: ntfsd
To: “File Systems Developers”
Sent: Friday, September 27, 2002 12:24 PM
Subject: [ntfsd] IRP Completion Rules – I/O Completion Routine Rules

> If we can get broad concensus on these rules (thanks Max), I’ll be MORE
than
> happy to post them on the web site in a prominent place.
>
> I’ve done some editing on Max’ original rules, limited their scope
> somewhat, and added a couple more.
>
> Corrections/suggestions/recommendations appreciated.
>
> Peter
> OSR
>
> ----------------------
>
> IRP Completion Rules
>
> - If a dispatch routine returns STATUS_PENDING, the IRP passed into the
> dispatch routine must be marked pending with IoMarkIrpPending().
> - If an IRP is marked pending with IoMarkIrpPending() in a dispatch
routine,
> that dispatch routine must return STATUS_PENDING.
> - If an IRP is to be marked pending, IoMarkIrpPending must be called
before
> the IRP is accessible from any context in which it might be completed.
> - If you complete the IRP in the dispatch routine, you must fill
> Irp->IoStatus.Status with the IRP’s completion status (this may NOT be
> STATUS_PENDING), you must fill Irp->IoStatus.Information with the number
of
> bytes read or written by the request if the request is being completed
with
> a success status (for data transfer operations and IOCTLs), and then you
> must call IoCompleteRequest(). On return from the dispatch routine, you
must
> return the same status that you filled into Irp->IoStatus.Status. Note
that
> in some cases Irp->IoStatus.Information can hold a pointer.
> - Once you call IoCompleteRequest(), you no longer “own” the IRP, and must
> not refer to any of its contents.
> - Irp->IoStatus.Status must be filled only just before IoCompleteRequest.
> You can use Irp->IoStatus as a temporary storage before this, assuming you
> do not pass the IRP to another driver.
> - Because of special logic in the I/O Manager’s completion handling code,
> drivers can also pass an IRP to another by “return IoCallDriver(.)”. In
this
> case, IoMarkIrpPending must not be called.
> - The following sequence is also valid, though slower. It is necessary as
a
> workaround for filtering some buggy drivers like NT4’s CDFS:
>
> IoMarkIrpPending(Irp);
> (VOID)IoCallDriver(BottomDeviceObject, Irp);
> return STATUS_PENDING;
>
> I/O Completion Routines
>
> - There are only three valid return codes from an I/O Completion Routine:
> STATUS_MORE_PROCESSING_REQUIRED, STATUS_SUCCESS, and
> STATUS_CONTINUE_COMPLETION (which is identical to STATUS_SUCCESS, see
> NTDDK.H)
>
> - STATUS_MORE_PROCESSING_REQUIRED means that IoCompleteRequest returns to
> its caller
> immediately. No further completion routines are called, and IRP is not
> returned to the I/O Manager.
>
> - If and only if the completion routine returns STATUS_SUCCESS (or
> STATUS_CONTINUE_COMPLETION) , then it must do the following:
>
> if( Irp->PendingReturned ) {
> IoMarkIrpPending(Irp);
> }
> - If your completion routine returns STATUS_MORE_PROCESSING_REQUIRED, your
> dispatch routine for that IRP (if you have one, that is, if you did not
> create the IRP in your driver) must either return STATUS_PENDING or it
must
> block until the completion routine has run (for example, waiting on an
event
> that is set from within the completion routine).
>
>
>
> —
> You are currently subscribed to ntfsd as: xxxxx@yoshimuni.com
> To unsubscribe send a blank email to %%email.unsub%%
>

“David J. Craig” wrote in message
news:xxxxx@ntfsd…
>


Thanks for the feedback, David.

> I know you cover this in the OSR courses, but maybe it will be helpful for
> new developers to understand how and why much of this works. I don’t
think
> Microsoft gives us the source to the IoManager so it is hard to understand
> some of this stuff.
>

Don’t forget the seminal article from The NT Insider on this:
http://www.osr.com/ntinsider/1997/iocomp/iocomp.htm

Peter
OSR

hi,
i am writing a file system filter driver and i have a doubt.i set a
completion routine befre calling the lower dirver. in the completion
routine sometimes i return status_more_processing_requred and sometimes i
return status_succes depending upon the irql at which the completion
routine is invoked(i have to schedule some post processing if i am invoked
at a higher irql).
what kind of status should i return while sending the irp down
in the dispatch routine(status_pending) or “return iocalldriver”.and do i
need to mark the irp as pendilng always in the dispatch routine or can i
mark it as pending in the completion routine only when i return
status_more_processing_reqd

regards
shobhit

If it is possible that you return STATUS_MORE_PROCESSING_REQUIRED in
your completion routine, in your dispatch routine you must mark the IRP
pending and return STATUS_PENDING.

Molly Brown
Microsoft Corporation

This posting is provided “AS IS” with no implied warranties and confers
no rights.

-----Original Message-----
From: shobhit [mailto:xxxxx@calsoftinc.com]
Sent: Friday, October 04, 2002 12:25 AM
To: File Systems Developers
Subject: [ntfsd] Re: IRP Completion Rules – I/O Completion Routine
Rules

hi,
i am writing a file system filter driver and i have a doubt.i set a
completion routine befre calling the lower dirver. in the completion
routine sometimes i return status_more_processing_requred and sometimes
i return status_succes depending upon the irql at which the completion
routine is invoked(i have to schedule some post processing if i am
invoked at a higher irql).
what kind of status should i return while sending the irp
down in the dispatch routine(status_pending) or “return
iocalldriver”.and do i need to mark the irp as pendilng always in the
dispatch routine or can i mark it as pending in the completion routine
only when i return status_more_processing_reqd

regards
shobhit


You are currently subscribed to ntfsd as: xxxxx@windows.microsoft.com
To unsubscribe send a blank email to %%email.unsub%%