Completion Routine at DISPATCH_LEVEL

Hi, everyone, I have a question about my SCSI filter driver. My filter is
a lower filter of tape drive. In this filter I intercept the SCSIOP_READ6
and SCSIOP_WRITE6 operations for encryption/decryption. In my current
IRP’s completion routine I need to build a new IRP and send it to another
driver for decryption. I also set a completion routine for this new IRP.
That driver for decryption uses some asynchronous operation. So the
IoCallDriver() routine simply returns STATUS_PENDING. The problem happened
when the current IRP completion routine is running at DISPATCH_LEVEL.
Since it is at DISPATCH_LEVEL, so I couldn’t use KeWaitForSingleObject()
to wait for the new IRP’s completion routine to be finished. In that way
my filter driver don’t know when this new IRP will be completed. In other
words I don’t know at what time my data will be decrypted. What can I do?
How can I handle the current IRP once the new IRP returns STATUS_PENDING?
Simple return STATUS_MORE_PROCESSING_REQUIRED?

Any help or idea will be appreciated. Thanks

Michael

Yes, return STATUS_MORE_PROCESSING_REQUIRED and complete the original
IRP in your completion routine for the secondary IRP.

Michael wrote:

Hi, everyone, I have a question about my SCSI filter driver. My filter is
a lower filter of tape drive. In this filter I intercept the SCSIOP_READ6
and SCSIOP_WRITE6 operations for encryption/decryption. In my current
IRP’s completion routine I need to build a new IRP and send it to another
driver for decryption. I also set a completion routine for this new IRP.
That driver for decryption uses some asynchronous operation. So the
IoCallDriver() routine simply returns STATUS_PENDING. The problem happened
when the current IRP completion routine is running at DISPATCH_LEVEL.
Since it is at DISPATCH_LEVEL, so I couldn’t use KeWaitForSingleObject()
to wait for the new IRP’s completion routine to be finished. In that way
my filter driver don’t know when this new IRP will be completed. In other
words I don’t know at what time my data will be decrypted. What can I do?
How can I handle the current IRP once the new IRP returns STATUS_PENDING?
Simple return STATUS_MORE_PROCESSING_REQUIRED?

Any help or idea will be appreciated. Thanks

Michael


Nick Ryan (MVP for DDK)

Thanks Nick, I’ll try this.

Michael

— Nick Ryan wrote: > Yes, return
STATUS_MORE_PROCESSING_REQUIRED and
> complete the original
> IRP in your completion routine for the secondary
> IRP.
>
> Michael wrote:
>
> > Hi, everyone, I have a question about my SCSI
> filter driver. My filter is
> > a lower filter of tape drive. In this filter I
> intercept the SCSIOP_READ6
> > and SCSIOP_WRITE6 operations for
> encryption/decryption. In my current
> > IRP’s completion routine I need to build a new IRP
> and send it to another
> > driver for decryption. I also set a completion
> routine for this new IRP.
> > That driver for decryption uses some asynchronous
> operation. So the
> > IoCallDriver() routine simply returns
> STATUS_PENDING. The problem happened
> > when the current IRP completion routine is running
> at DISPATCH_LEVEL.
> > Since it is at DISPATCH_LEVEL, so I couldn’t use
> KeWaitForSingleObject()
> > to wait for the new IRP’s completion routine to be
> finished. In that way
> > my filter driver don’t know when this new IRP will
> be completed. In other
> > words I don’t know at what time my data will be
> decrypted. What can I do?
> > How can I handle the current IRP once the new IRP
> returns STATUS_PENDING?
> > Simple return STATUS_MORE_PROCESSING_REQUIRED?
> >
> > Any help or idea will be appreciated. Thanks
> >
> > Michael
> >
> >
>
> –
> Nick Ryan (MVP for DDK)
>
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> You are currently subscribed to ntdev as:
> xxxxx@yahoo.ca
> To unsubscribe send a blank email to
xxxxx@lists.osr.com

______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca

This is an excellent question that is essentially asking for help with
asynchronous operations as a whole. Allow me to try to explain what I
understand you are doing, and then provide a solution (which others will
undoubtably update ;)):

Tape Device Stack:
TAPE.SYS
YourFilter.SYS
PortDriver.SYS

Discussing now YourFilter only:

  1. When receive READ6, set completion routine Read6Complete().

When Read6Complete() occurs:
2.1) This is where you are asking about how to not use KeWait()
2.2) Prepare the irp for the decryption routine.
2.3) Setup a structure with:
2.3.1) your device object(*)
2.3.2) the original READ6 irp pointer
2.3.3) any context you need for the new decryption irp
2.4) Set completion routine context to this structure.
2.5) Set completion routine for decryption irp to
DecryptRead6Complete().
2.6) Set STATUS_PENDING and such appropriately if required – IMPORTANT.
2.7) Send irp to decryption routine and return STATUS_PENDING
unconditionally.

When DecryptRead6Complete() occurs:
3.1) Extract your device object and original irp pointer
3.3) Copy any data as required.
3.3) Cleanup irp you sent to decryption driver
3.3.1) Free the decryption irp or store for later use.
3.3.2) Free any resources related to decryption irp or store for later
use.
3.4) Call IoCompleteRequest() on the original irp
3.5) Return STATUS_PENDING, since you don’t want decryption irp
completed.

Note that you return STATUS_PENDING in both completion routines. That’s
OK, as you end up calling IoCompleteRequest() again in 3.4, which gets
the original irp to complete. While this method of asynchronous
operations is somewhat more complex that a synchronous IO model, it
allows you significantly more flexibility in how you process IO.

Hth,
.

(*) If you allocate the irp, your completion routine won’t be given a
valid device object. It’s weird, but it’s because the completion
routine’s device object comes from the *previous* irpstack (or, to look
at it another way, the completion routine is set in the *next*
irpstack). So, because you don’t have an irpstack, your devobj is set
to NULL in the completion routine. Fun, eh?
(**) I only get the digest version of this list once a day, so expect my
responses to be somewhat delayed.

-----Original Message-----
From: Michael [mailto:xxxxx@yahoo.ca]
Sent: Thursday, September 04, 2003 8:42 PM
Subject: Completion Routine at DISPATCH_LEVEL

Hi, everyone, I have a question about my SCSI filter driver. My filter
is
a lower filter of tape drive. In this filter I intercept the
SCSIOP_READ6
and SCSIOP_WRITE6 operations for encryption/decryption. In my current
IRP’s completion routine I need to build a new IRP and send it to
another
driver for decryption. I also set a completion routine for this new IRP.
That driver for decryption uses some asynchronous operation. So the
IoCallDriver() routine simply returns STATUS_PENDING. The problem
happened
when the current IRP completion routine is running at DISPATCH_LEVEL.
Since it is at DISPATCH_LEVEL, so I couldn’t use KeWaitForSingleObject()
to wait for the new IRP’s completion routine to be finished. In that way
my filter driver don’t know when this new IRP will be completed. In
other
words I don’t know at what time my data will be decrypted. What can I
do?
How can I handle the current IRP once the new IRP returns
STATUS_PENDING?
Simple return STATUS_MORE_PROCESSING_REQUIRED?

Any help or idea will be appreciated. Thanks

Michael

Basically correct but you can never return STATUS_PENDING from a
completion routine; you must return STATUS_MORE_PROCESSING_REQUIRED to
abort completion processing. It’s in his original dispatch routine he
has to mark the IRP pending, call it down, and return STATUS_PENDING.

Henry Gabryjelski wrote:

This is an excellent question that is essentially asking for help with
asynchronous operations as a whole. Allow me to try to explain what I
understand you are doing, and then provide a solution (which others will
undoubtably update ;)):

Tape Device Stack:
TAPE.SYS
YourFilter.SYS
PortDriver.SYS

Discussing now YourFilter only:

  1. When receive READ6, set completion routine Read6Complete().

When Read6Complete() occurs:
2.1) This is where you are asking about how to not use KeWait()
2.2) Prepare the irp for the decryption routine.
2.3) Setup a structure with:
2.3.1) your device object(*)
2.3.2) the original READ6 irp pointer
2.3.3) any context you need for the new decryption irp
2.4) Set completion routine context to this structure.
2.5) Set completion routine for decryption irp to
DecryptRead6Complete().
2.6) Set STATUS_PENDING and such appropriately if required – IMPORTANT.
2.7) Send irp to decryption routine and return STATUS_PENDING
unconditionally.

When DecryptRead6Complete() occurs:
3.1) Extract your device object and original irp pointer
3.3) Copy any data as required.
3.3) Cleanup irp you sent to decryption driver
3.3.1) Free the decryption irp or store for later use.
3.3.2) Free any resources related to decryption irp or store for later
use.
3.4) Call IoCompleteRequest() on the original irp
3.5) Return STATUS_PENDING, since you don’t want decryption irp
completed.

Note that you return STATUS_PENDING in both completion routines. That’s
OK, as you end up calling IoCompleteRequest() again in 3.4, which gets
the original irp to complete. While this method of asynchronous
operations is somewhat more complex that a synchronous IO model, it
allows you significantly more flexibility in how you process IO.

Hth,
.

(*) If you allocate the irp, your completion routine won’t be given a
valid device object. It’s weird, but it’s because the completion
routine’s device object comes from the *previous* irpstack (or, to look
at it another way, the completion routine is set in the *next*
irpstack). So, because you don’t have an irpstack, your devobj is set
to NULL in the completion routine. Fun, eh?
(**) I only get the digest version of this list once a day, so expect my
responses to be somewhat delayed.

-----Original Message-----
From: Michael [mailto:xxxxx@yahoo.ca]
Sent: Thursday, September 04, 2003 8:42 PM
Subject: Completion Routine at DISPATCH_LEVEL

Hi, everyone, I have a question about my SCSI filter driver. My filter
is
a lower filter of tape drive. In this filter I intercept the
SCSIOP_READ6
and SCSIOP_WRITE6 operations for encryption/decryption. In my current
IRP’s completion routine I need to build a new IRP and send it to
another
driver for decryption. I also set a completion routine for this new IRP.
That driver for decryption uses some asynchronous operation. So the
IoCallDriver() routine simply returns STATUS_PENDING. The problem
happened
when the current IRP completion routine is running at DISPATCH_LEVEL.
Since it is at DISPATCH_LEVEL, so I couldn’t use KeWaitForSingleObject()
to wait for the new IRP’s completion routine to be finished. In that way
my filter driver don’t know when this new IRP will be completed. In
other
words I don’t know at what time my data will be decrypted. What can I
do?
How can I handle the current IRP once the new IRP returns
STATUS_PENDING?
Simple return STATUS_MORE_PROCESSING_REQUIRED?

Any help or idea will be appreciated. Thanks

Michael


Nick Ryan (MVP for DDK)

Am I right that you send a second IRP to the decryptor driver with a completion
routine?

Then the completion routine (yours) will be called at decryption done. Call
IoCompleteRequest for the first IRP from it.

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

----- Original Message -----
From: “Michael”
To: “Windows System Software Developers Interest List”
Sent: Friday, September 05, 2003 7:41 AM
Subject: [ntdev] Completion Routine at DISPATCH_LEVEL

> Hi, everyone, I have a question about my SCSI filter driver. My filter is
> a lower filter of tape drive. In this filter I intercept the SCSIOP_READ6
> and SCSIOP_WRITE6 operations for encryption/decryption. In my current
> IRP’s completion routine I need to build a new IRP and send it to another
> driver for decryption. I also set a completion routine for this new IRP.
> That driver for decryption uses some asynchronous operation. So the
> IoCallDriver() routine simply returns STATUS_PENDING. The problem happened
> when the current IRP completion routine is running at DISPATCH_LEVEL.
> Since it is at DISPATCH_LEVEL, so I couldn’t use KeWaitForSingleObject()
> to wait for the new IRP’s completion routine to be finished. In that way
> my filter driver don’t know when this new IRP will be completed. In other
> words I don’t know at what time my data will be decrypted. What can I do?
> How can I handle the current IRP once the new IRP returns STATUS_PENDING?
> Simple return STATUS_MORE_PROCESSING_REQUIRED?
>
> Any help or idea will be appreciated. Thanks
>
> Michael
>
> —
> Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
>
> You are currently subscribed to ntdev as: xxxxx@storagecraft.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

True, my mistake. I knew there would be updates to what I write. :wink:

Thanks!
.

-----Original Message-----
From: Nick Ryan [mailto:xxxxx@nryan.com]
Sent: Friday, September 05, 2003 10:55 AM
Subject: Re: Completion Routine at DISPATCH_LEVEL

Basically correct but you can never return STATUS_PENDING from a
completion routine; you must return STATUS_MORE_PROCESSING_REQUIRED to
abort completion processing. It’s in his original dispatch routine he
has to mark the IRP pending, call it down, and return STATUS_PENDING.

Henry Gabryjelski wrote:

This is an excellent question that is essentially asking for help with
asynchronous operations as a whole. Allow me to try to explain what I
understand you are doing, and then provide a solution (which others
will
undoubtably update ;)):

Tape Device Stack:
TAPE.SYS
YourFilter.SYS
PortDriver.SYS

Discussing now YourFilter only:

  1. When receive READ6, set completion routine Read6Complete().

When Read6Complete() occurs:
2.1) This is where you are asking about how to not use KeWait()
2.2) Prepare the irp for the decryption routine.
2.3) Setup a structure with:
2.3.1) your device object(*)
2.3.2) the original READ6 irp pointer
2.3.3) any context you need for the new decryption irp
2.4) Set completion routine context to this structure.
2.5) Set completion routine for decryption irp to
DecryptRead6Complete().
2.6) Set STATUS_PENDING and such appropriately if required –
IMPORTANT.
2.7) Send irp to decryption routine and return STATUS_PENDING
unconditionally.

When DecryptRead6Complete() occurs:
3.1) Extract your device object and original irp pointer
3.3) Copy any data as required.
3.3) Cleanup irp you sent to decryption driver
3.3.1) Free the decryption irp or store for later use.
3.3.2) Free any resources related to decryption irp or store for later
use.
3.4) Call IoCompleteRequest() on the original irp
3.5) Return STATUS_PENDING, since you don’t want decryption irp
completed.

Note that you return STATUS_PENDING in both completion routines.
That’s
OK, as you end up calling IoCompleteRequest() again in 3.4, which gets
the original irp to complete. While this method of asynchronous
operations is somewhat more complex that a synchronous IO model, it
allows you significantly more flexibility in how you process IO.

Hth,
.

(*) If you allocate the irp, your completion routine won’t be given a
valid device object. It’s weird, but it’s because the completion
routine’s device object comes from the *previous* irpstack (or, to
look
at it another way, the completion routine is set in the *next*
irpstack). So, because you don’t have an irpstack, your devobj is set
to NULL in the completion routine. Fun, eh?
(**) I only get the digest version of this list once a day, so expect
my
responses to be somewhat delayed.

-----Original Message-----
From: Michael [mailto:xxxxx@yahoo.ca]
Sent: Thursday, September 04, 2003 8:42 PM
Subject: Completion Routine at DISPATCH_LEVEL

Hi, everyone, I have a question about my SCSI filter driver. My filter
is
a lower filter of tape drive. In this filter I intercept the
SCSIOP_READ6
and SCSIOP_WRITE6 operations for encryption/decryption. In my current
IRP’s completion routine I need to build a new IRP and send it to
another
driver for decryption. I also set a completion routine for this new
IRP.
That driver for decryption uses some asynchronous operation. So the
IoCallDriver() routine simply returns STATUS_PENDING. The problem
happened
when the current IRP completion routine is running at DISPATCH_LEVEL.
Since it is at DISPATCH_LEVEL, so I couldn’t use
KeWaitForSingleObject()
to wait for the new IRP’s completion routine to be finished. In that
way
my filter driver don’t know when this new IRP will be completed. In
other
words I don’t know at what time my data will be decrypted. What can I
do?
How can I handle the current IRP once the new IRP returns
STATUS_PENDING?
Simple return STATUS_MORE_PROCESSING_REQUIRED?

Any help or idea will be appreciated. Thanks

Michael


Nick Ryan (MVP for DDK)