IoMarkIrpPending in completion routine

I am writing a filter driver.
I am setting a completion routine before calling IoCallDriver

Am I allowed to call
IoMarkIrpPending in my completion routine (after the file system driver has
completed the IRP),
then make some user-mode processing,
and then call IoCompleteRequest ?

Are there any limitations or rules I should follow ?

You are surely allowed to call IoMarkIrpPending in completion routine. But
you must understand consequences of doing that. If you explain what do you
want to achieve we could help you with some advice.

Generally you can mark EVERY irp pending (with IoMarkIrpPending) though
doing that may hit entire system performance greatly.

-htfv

----- Original Message -----
From: “Nir Livni”
To: “File Systems Developers”
Sent: Thursday, September 26, 2002 1:52 PM
Subject: [ntfsd] IoMarkIrpPending in completion routine

> I am writing a filter driver.
> I am setting a completion routine before calling IoCallDriver
>
> Am I allowed to call
> IoMarkIrpPending in my completion routine (after the file system driver
has
> completed the IRP),
> then make some user-mode processing,
> and then call IoCompleteRequest ?
>
> Are there any limitations or rules I should follow ?
>
>
>
> —
> You are currently subscribed to ntfsd as: xxxxx@vba.com.by
> To unsubscribe send a blank email to %%email.unsub%%
>

> IoMarkIrpPending in my completion routine (after the file system
driver has

completed the IRP),

You can, but in a special way.

THE IRP HANDLING RULES:

(can somebody put them to a web page?)

  • IoMarkIrpPending must be called before the IRP will arrive to a
    context (queue or such), from where it can be completed in an async
    way by other code paths (DPCs or such).
  • IoMarkIrpPending requires STATUS_PENDING to be returned, and vice
    versa. No exceptions from this.
  • if you want to complete the IRP just in the dispatch routine, return
    the same status as you put to Irp->IoStatus.Status. This cannot be
    STATUS_PENDING. Do not call IoMarkIrpPending.
  • Irp->IoStatus.Status must be filled only just before
    IoCompleteRequest. You can use Irp->IoStatus as a temporary storage
    before this :slight_smile: (at least if you do not pass the IRP down). Also note
    that Irp->IoStatus.Information can hold a pointer (it really holds it
    for some PnP IRPs).
  • drivers which are not bottom-most, including all filters, can also
    pass the IRP down by “return IoCallDriver”. In this case,
    IoMarkIrpPending must not be called (regardless of NT4’s CLASS2 code
    which had such a bug, it was not hit only because SCSIPORT always
    returned STATUS_PENDING, and my full SCSI port code hit it more or
    less soon).
  • this 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;

  • now the completion routines. Only 2 return values are valid.
    STATUS_MORE_PROCESSING_REQUIRED and STATUS_SUCCESS.
  • STATUS_MORE_PROCESSING_REQUIRED means that IoCompleteRequest exits
    immediately. Next completion routines are not called, and IRP is not
    passed to IO manager for destruction.
  • if and only if the completion routine returns STATUS_SUCCESS, then
    it must do the following:

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

Just copy-paste it. It is necessary. Too bad IoCompleteRequest does
not this itself.

  • now the kinds of IRPs. “Full-blown” and “not-full-blown”.
  • first are created by IoBuildDeviceIoControlRequest and
    IoBuildSynchronousFsdRequest, including the IO syscalls called from
    user mode or by Zwxxx (NtxxxFile functions use the Ioxxx functions are
    mentioned). These IRPs are associated with the thread, and
    IoGetRequestorProcess works for them. These IRPs must be passed to IO
    manager for destruction by returning STATUS_SUCCESS from the
    completion routine. IoFreeIrp cannot be called for them.
  • “not-full-blown” IRPs are created by IoBuildAsynchronousFsdRequest
    and IoAllocateIrp. They are not associated with any thread. They
    cannot be passed to IO manager for destruction, the completion routine
    must return STATUS_MORE_PROCESSING_REQUIRED. They must be freed by
    IoFreeIrp, possibly in the completion routine.
  • if you send the IRP down to some driver, you can use any way of the
    above ones. The driver will not be interested in how the IRP coming
    from above was built.
  • for first way, create an event, pass it to
    IoBuildDeviceIoControlRequest, then call IoCallDriver, then wait for
    event. IRP’s result will be in IO_STATUS_BLOCK passed to
    IoBuildDeviceIoControlRequest.
  • for second way, create an event, write a completion routine of:

KeSetEvent((PKEVENT)Context, IO_xxx_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;

then call IoAllocateIrp, then IoSetCompletionRoutine with event as a
context, then call IoCallDriver, then wait for event. After this,
IRP’s result is in Irp->IoStatus. You can either free the IRP by
IoFreeIrp now, or call IoReuseIrp and then reuse the IRP for next
calls, calling IoFreeIrp later.

  • now Irp->RequestorMode. It governs how the buffer pointer checks are
    made in the drivers which use Irp->UserBuffer - like FSDs. If mode is
    KernelMode, then no checks are made. If mode is UserMode, then
    Irp->UserBuffer is probed to be user mode pointer. So, for your own
    IRPs which fill Irp->UserBuffer, set Irp->RequestorMode to KernelMode.
  • note that some stacks like 1394 require Irp->RequestorMode to be
    KernelMode.

Max

Max, per your request I pasted your IRP handling rules at the bottom of my driver dev tip page:
http://students.cs.byu.edu/~nbushman/drivers.htm
I’ll pretty-it-up later.

Nate

-----Original Message-----
From: Maxim S. Shatskih [mailto:xxxxx@storagecraft.com]
Sent: Thursday, September 26, 2002 4:54 PM
To: File Systems Developers
Subject: [ntfsd] Re: IoMarkIrpPending in completion routine

IoMarkIrpPending in my completion routine (after the file system
driver has
completed the IRP),

You can, but in a special way.

THE IRP HANDLING RULES:

(can somebody put them to a web page?)

  • IoMarkIrpPending must be called before the IRP will arrive to a
    context (queue or such), from where it can be completed in an async
    way by other code paths (DPCs or such).
  • IoMarkIrpPending requires STATUS_PENDING to be returned, and vice
    versa. No exceptions from this.
  • if you want to complete the IRP just in the dispatch routine, return
    the same status as you put to Irp->IoStatus.Status. This cannot be
    STATUS_PENDING. Do not call IoMarkIrpPending.
  • Irp->IoStatus.Status must be filled only just before
    IoCompleteRequest. You can use Irp->IoStatus as a temporary storage
    before this :slight_smile: (at least if you do not pass the IRP down). Also note
    that Irp->IoStatus.Information can hold a pointer (it really holds it
    for some PnP IRPs).
  • drivers which are not bottom-most, including all filters, can also
    pass the IRP down by “return IoCallDriver”. In this case,
    IoMarkIrpPending must not be called (regardless of NT4’s CLASS2 code
    which had such a bug, it was not hit only because SCSIPORT always
    returned STATUS_PENDING, and my full SCSI port code hit it more or
    less soon).
  • this 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;

  • now the completion routines. Only 2 return values are valid.
    STATUS_MORE_PROCESSING_REQUIRED and STATUS_SUCCESS.
  • STATUS_MORE_PROCESSING_REQUIRED means that IoCompleteRequest exits
    immediately. Next completion routines are not called, and IRP is not
    passed to IO manager for destruction.
  • if and only if the completion routine returns STATUS_SUCCESS, then
    it must do the following:

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

Just copy-paste it. It is necessary. Too bad IoCompleteRequest does
not this itself.

  • now the kinds of IRPs. “Full-blown” and “not-full-blown”.
  • first are created by IoBuildDeviceIoControlRequest and
    IoBuildSynchronousFsdRequest, including the IO syscalls called from
    user mode or by Zwxxx (NtxxxFile functions use the Ioxxx functions are
    mentioned). These IRPs are associated with the thread, and
    IoGetRequestorProcess works for them. These IRPs must be passed to IO
    manager for destruction by returning STATUS_SUCCESS from the
    completion routine. IoFreeIrp cannot be called for them.
  • “not-full-blown” IRPs are created by IoBuildAsynchronousFsdRequest
    and IoAllocateIrp. They are not associated with any thread. They
    cannot be passed to IO manager for destruction, the completion routine
    must return STATUS_MORE_PROCESSING_REQUIRED. They must be freed by
    IoFreeIrp, possibly in the completion routine.
  • if you send the IRP down to some driver, you can use any way of the
    above ones. The driver will not be interested in how the IRP coming
    from above was built.
  • for first way, create an event, pass it to
    IoBuildDeviceIoControlRequest, then call IoCallDriver, then wait for
    event. IRP’s result will be in IO_STATUS_BLOCK passed to
    IoBuildDeviceIoControlRequest.
  • for second way, create an event, write a completion routine of:

KeSetEvent((PKEVENT)Context, IO_xxx_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;

then call IoAllocateIrp, then IoSetCompletionRoutine with event as a
context, then call IoCallDriver, then wait for event. After this,
IRP’s result is in Irp->IoStatus. You can either free the IRP by
IoFreeIrp now, or call IoReuseIrp and then reuse the IRP for next
calls, calling IoFreeIrp later.

  • now Irp->RequestorMode. It governs how the buffer pointer checks are
    made in the drivers which use Irp->UserBuffer - like FSDs. If mode is
    KernelMode, then no checks are made. If mode is UserMode, then
    Irp->UserBuffer is probed to be user mode pointer. So, for your own
    IRPs which fill Irp->UserBuffer, set Irp->RequestorMode to KernelMode.
  • note that some stacks like 1394 require Irp->RequestorMode to be
    KernelMode.

Max


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

“Nate Bushman” wrote in message
news:xxxxx@ntfsd…

Max, per your request I pasted your IRP handling rules at the bottom of my
driver dev tip page:
http://students.cs.byu.edu/~nbushman/drivers.htm
I’ll pretty-it-up later.

I hope you also post Ravi’s Rules for pending IRPs from a recent posting to
this list entitled:

Re: Marking an IRP as pending in a file system filter driver

It’s the best summary I’ve seen lately.

Carl

Yeah, I’ll post 'em

See my separate note on this topic

Peter
OSR

“Maxim S. Shatskih” wrote in message
news:xxxxx@ntfsd…
>
> > IoMarkIrpPending in my completion routine (after the file system
> driver has
> > completed the IRP),
>
> You can, but in a special way.
>
>
> THE IRP HANDLING RULES:
>
> (can somebody put them to a web page?)
>
> - IoMarkIrpPending must be called before the IRP will arrive to a
> context (queue or such), from where it can be completed in an async
> way by other code paths (DPCs or such).
> - IoMarkIrpPending requires STATUS_PENDING to be returned, and vice
> versa. No exceptions from this.
> - if you want to complete the IRP just in the dispatch routine, return
> the same status as you put to Irp->IoStatus.Status. This cannot be
> STATUS_PENDING. Do not call IoMarkIrpPending.
> - Irp->IoStatus.Status must be filled only just before
> IoCompleteRequest. You can use Irp->IoStatus as a temporary storage
> before this :slight_smile: (at least if you do not pass the IRP down). Also note
> that Irp->IoStatus.Information can hold a pointer (it really holds it
> for some PnP IRPs).
> - drivers which are not bottom-most, including all filters, can also
> pass the IRP down by “return IoCallDriver”. In this case,
> IoMarkIrpPending must not be called (regardless of NT4’s CLASS2 code
> which had such a bug, it was not hit only because SCSIPORT always
> returned STATUS_PENDING, and my full SCSI port code hit it more or
> less soon).
> - this 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;
>
> - now the completion routines. Only 2 return values are valid.
> STATUS_MORE_PROCESSING_REQUIRED and STATUS_SUCCESS.
> - STATUS_MORE_PROCESSING_REQUIRED means that IoCompleteRequest exits
> immediately. Next completion routines are not called, and IRP is not
> passed to IO manager for destruction.
> - if and only if the completion routine returns STATUS_SUCCESS, then
> it must do the following:
>
> if( Irp->PendingReturned )
> IoMarkIrpPending(Irp);
>
> Just copy-paste it. It is necessary. Too bad IoCompleteRequest does
> not this itself.
>
> - now the kinds of IRPs. “Full-blown” and “not-full-blown”.
> - first are created by IoBuildDeviceIoControlRequest and
> IoBuildSynchronousFsdRequest, including the IO syscalls called from
> user mode or by Zwxxx (NtxxxFile functions use the Ioxxx functions are
> mentioned). These IRPs are associated with the thread, and
> IoGetRequestorProcess works for them. These IRPs must be passed to IO
> manager for destruction by returning STATUS_SUCCESS from the
> completion routine. IoFreeIrp cannot be called for them.
> - “not-full-blown” IRPs are created by IoBuildAsynchronousFsdRequest
> and IoAllocateIrp. They are not associated with any thread. They
> cannot be passed to IO manager for destruction, the completion routine
> must return STATUS_MORE_PROCESSING_REQUIRED. They must be freed by
> IoFreeIrp, possibly in the completion routine.
> - if you send the IRP down to some driver, you can use any way of the
> above ones. The driver will not be interested in how the IRP coming
> from above was built.
> - for first way, create an event, pass it to
> IoBuildDeviceIoControlRequest, then call IoCallDriver, then wait for
> event. IRP’s result will be in IO_STATUS_BLOCK passed to
> IoBuildDeviceIoControlRequest.
> - for second way, create an event, write a completion routine of:
>
> KeSetEvent((PKEVENT)Context, IO_xxx_INCREMENT, FALSE);
> return STATUS_MORE_PROCESSING_REQUIRED;
>
> then call IoAllocateIrp, then IoSetCompletionRoutine with event as a
> context, then call IoCallDriver, then wait for event. After this,
> IRP’s result is in Irp->IoStatus. You can either free the IRP by
> IoFreeIrp now, or call IoReuseIrp and then reuse the IRP for next
> calls, calling IoFreeIrp later.
>
> - now Irp->RequestorMode. It governs how the buffer pointer checks are
> made in the drivers which use Irp->UserBuffer - like FSDs. If mode is
> KernelMode, then no checks are made. If mode is UserMode, then
> Irp->UserBuffer is probed to be user mode pointer. So, for your own
> IRPs which fill Irp->UserBuffer, set Irp->RequestorMode to KernelMode.
> - note that some stacks like 1394 require Irp->RequestorMode to be
> KernelMode.
>
> Max
>
>
>
>
>