STATUS_PENDING(IoCallDriver())

Hi,

I’m writing an encryption filter driver on Win2k.
My filter driver hooks RDR and encrypts/decrypts
network file traffic.
In my IRP_MJ_READ function, I must get a file
size for encryption prior to reading file data.
In order to get the file size, I roll my own Irp
and call IoCallDriver(). But IoCallDriver() returns
STATUS_PENDING and somehow my completion routine
is never called.

My code is as follows.

NTSTATUS NTAPI
MyGetFileSize(
IN PDEVICE_OBJECT pDeviceObject,
IN PFILE_OBJECT pFileObject,
OUT PLARGE_INTEGER pFileSize)
{
// Rolling my own Irp.
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(pIRP, MyCompleteRoutine,
NULL, TRUE, TRUE, TRUE);
ntResult = IoCallDriver(pDeviceObject, pIRP);
if(ntResult == STATUS_PENDING){
ntResult = KeWaitForSingleObject(
&Event, Suspended, KernelMode, FALSE, 0);
// this function never returns because my completion
// routine is never called.
}else{
ntResult = KeWaitForSingleObject(
&Event, Executive, KernelMode, TRUE, 0);
}
}

NTSTATUS MyCompleteRoutine(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIRP,
IN PVOID pContext)
{
if(pIRP->PendingReturned){
IoMarkIrpPending(pIRP);
}
*(pIRP->UserIosb) = pIRP->IoStatus;
KeSetEvent(pIRP->UserEvent, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}

What should I do when IoCallDriver() returns STATUS_PENDING?
Does anyone have the similar problem (experience) as mine?
Any help is greately appreciated.

Regards,

Takashi


You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com

I found out the reason why IoCallDriver() returns STATUS_PENDING when
I roll my own Irps to the lower redirector on Win2k.
When FO_SYNCHRONOUS_IO bit is not set in FileObject->Flags,
IoCallDriver() returns STATUS_PENDING.
So I was able to solve this problem by setting FO_SYNCHRONOUS_IO bit
prior to calling IoCallDriver().
This problem didn’t happen when I was writing my encryption filter
driver on Windows NT.

Takashi

I’m writing an encryption filter driver on Win2k.
My filter driver hooks RDR and encrypts/decrypts
network file traffic.
In my IRP_MJ_READ function, I must get a file
size for encryption prior to reading file data.
In order to get the file size, I roll my own Irp
and call IoCallDriver(). But IoCallDriver() returns
STATUS_PENDING and somehow my completion routine
is never called.
What should I do when IoCallDriver() returns STATUS_PENDING?
Does anyone have the similar problem (experience) as mine?
Any help is greately appreciated.


You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Just a caution to those who build drivers relying upon specific behavior:
there is NOTHING that enforces or guarantees this behavior.

The NT I/O model is asynchronous. That was an important design feature.
Applications (or in this case, your driver) MAY ask for synchronous I/O and
the underlying driver MAY actually provide synchronous I/O but there is
nothing that requires or enforces this. For applications, this is normally
handled by the I/O Manager. For another driver, it is the driver’s
responsibility to handle this.

Thus, even if you set the FO_SYNCHRONOUS_IO bit in the file object, the
underlying driver may still choose to implement the I/O asynchronously.
Thus, it is imprudent to generalize on “this is the right way to do things”
based solely upon the specific behavior of a single driver.

Regards,

Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com

-----Original Message-----
From: xxxxx@itg.hitachi.co.jp [mailto:xxxxx@itg.hitachi.co.jp]
Sent: Sunday, January 21, 2001 6:24 AM
To: File Systems Developers
Subject: [ntfsd] Re: STATUS_PENDING(IoCallDriver())

I found out the reason why IoCallDriver() returns STATUS_PENDING when
I roll my own Irps to the lower redirector on Win2k.
When FO_SYNCHRONOUS_IO bit is not set in FileObject->Flags,
IoCallDriver() returns STATUS_PENDING.
So I was able to solve this problem by setting FO_SYNCHRONOUS_IO bit
prior to calling IoCallDriver().
This problem didn’t happen when I was writing my encryption filter
driver on Windows NT.

Takashi

I’m writing an encryption filter driver on Win2k.
My filter driver hooks RDR and encrypts/decrypts
network file traffic.
In my IRP_MJ_READ function, I must get a file
size for encryption prior to reading file data.
In order to get the file size, I roll my own Irp
and call IoCallDriver(). But IoCallDriver() returns
STATUS_PENDING and somehow my completion routine
is never called.
What should I do when IoCallDriver() returns STATUS_PENDING?
Does anyone have the similar problem (experience) as mine?
Any help is greately appreciated.


You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Dear Tony!

Thank you for the response. After I found out the
FO_SYNCHRONOUS_IO bit by using windbg, I reread
“Windows NT File System Internals” by Rajeev Nagar
and I noticed IoIsOperationSynchronous() and
the IRP_SYNCHRONOUS_API bit.

Finally I chose to set the IRP_SYNCHRONOUS_API bit
in my own Irp instead of setting the FO_SYNCHRONOUS_IO
bit in the file object when I roll my own Irps to the
lower redirector. Now it seems that my filter driver
is working fine though there are still some bugs
I must fix.

I know this is not the perfect right way to do things,
but I couldn’t specify the reason why my completion
routine is never called when the lower driver returns
STATUS_PENDING. I don’t recommend this way to anyone.
This is just an example how I could avoid a problem
in an ad hoc way.

Regards,

Takashi


You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Takashi,

In your original mail you said that your completion routine hadn’t been
invoked. Marking the IRP as IRP_SYNCHRONOUS_API cannot fix such a problem. I
suspect the following marked line in your completion routine:

NTSTATUS MyCompleteRoutine(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIRP,
IN PVOID pContext)
{
if(pIRP->PendingReturned){
IoMarkIrpPending(pIRP);
}
*(pIRP->UserIosb) = pIRP->IoStatus; -------------------------
KeSetEvent(pIRP->UserEvent, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}

For an async operation you cannot reference pIRP->UserIosb because you might
be in the wrong context. So, changing the operation to synchronous might
have just fixed an exception in your routine.

Sara

----- Original Message -----
From:
To: “File Systems Developers”
Sent: Tuesday, January 23, 2001 9:21 PM
Subject: [ntfsd] Re: STATUS_PENDING(IoCallDriver())

> Dear Tony!
>
> Thank you for the response. After I found out the
> FO_SYNCHRONOUS_IO bit by using windbg, I reread
> “Windows NT File System Internals” by Rajeev Nagar
> and I noticed IoIsOperationSynchronous() and
> the IRP_SYNCHRONOUS_API bit.
>
> Finally I chose to set the IRP_SYNCHRONOUS_API bit
> in my own Irp instead of setting the FO_SYNCHRONOUS_IO
> bit in the file object when I roll my own Irps to the
> lower redirector. Now it seems that my filter driver
> is working fine though there are still some bugs
> I must fix.
>
> I know this is not the perfect right way to do things,
> but I couldn’t specify the reason why my completion
> routine is never called when the lower driver returns
> STATUS_PENDING. I don’t recommend this way to anyone.
> This is just an example how I could avoid a problem
> in an ad hoc way.
>
> Regards,
>
> Takashi
>
> —
> You are currently subscribed to ntfsd as: xxxxx@veritas.com
> To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com
>


You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Hi, Takashi:

NTSTATUS NTAPI
MyGetFileSize(
IN PDEVICE_OBJECT pDeviceObject,
IN PFILE_OBJECT pFileObject,
OUT PLARGE_INTEGER pFileSize)
{
// Rolling my own Irp.
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
IoSetCompletionRoutine(pIRP, MyCompleteRoutine,
NULL, TRUE, TRUE, TRUE);
ntResult = IoCallDriver(pDeviceObject, pIRP);
if(ntResult == STATUS_PENDING){
ntResult = KeWaitForSingleObject(
&Event, Suspended, KernelMode, FALSE, 0);
// this function never returns because my completion
// routine is never called.
}else{
ntResult = KeWaitForSingleObject(
&Event, Executive, KernelMode, TRUE, 0);

I don´t know why you call KeWaitForSingleObject even when IoCallDriver does
not return STATUS_PENDING. This should be necessary only when STATUS_PENDING
is returned.

NTSTATUS MyCompleteRoutine(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIRP,
IN PVOID pContext)
{
if(pIRP->PendingReturned){
IoMarkIrpPending(pIRP);
}

I´m almost sure this is incorrect. I had the same problem and this caused a
page fault. Maybe in your case the effect is that your completion routine
seems to be never called.

The problem is the following: since you are rolling your own IRP, I assume
you allocate it and initialize it, so, that means your device is the first
one in the stack. IoMarkIrpPending seems to access the PREVIOUS stack
location, and since yours is the first one, just imagine what a mess could
result from this.

And just another remark: remember to pass the IRP to the device you´re
attached to, never to other device such as the one taken from
FileObject->DeviceObject, since then that IRP would incur in unneeded
overhead and you could be facing reentrancy problems (that IRP will arrive
to your driver).

I use the following code successfully to retrieve the file size from a file
(using a standard info query):

/*=======================================================================*/

static NTSTATUS irpCompletion(
PDEVICE_OBJECT deviceObject,
PIRP irp,
PVOID context
)
{
*irp->UserIosb = irp->IoStatus; // Copy status information to
// the user

KeSetEvent(irp->UserEvent, 0, FALSE); // Signal event

IoFreeIrp(irp); // Free IRP

return STATUS_MORE_PROCESSING_REQUIRED; // Tell the I/O manager to stop
}

/*=======================================================================*/

static BOOLEAN irpGetInfo(
PDEVICE_OBJECT hookedDevice,
PFILE_OBJECT fileObject,
PVOID buffer,
ULONG bufferLength,
FILE_INFORMATION_CLASS fileInfoClass
)
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;

irp = IoAllocateIrp(hookedDevice->StackSize, FALSE);

KeInitializeEvent(&event, NotificationEvent, FALSE);

RtlZeroMemory(buffer, bufferLength);

irp->AssociatedIrp.SystemBuffer = buffer;
irp->UserEvent = &event;
irp->UserIosb = &ioStatus;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = fileObject;
irp->RequestorMode = KernelMode;
irp->Flags = IRP_NOCACHE;

irpSp = IoGetNextIrpStackLocation(irp);
irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
irpSp->MinorFunction = 0;
irpSp->DeviceObject = hookedDevice;
irpSp->FileObject = fileObject;
irpSp->Parameters.QueryFile.Length = bufferLength;
irpSp->Parameters.QueryFile.FileInformationClass = fileInfoClass;

IoSetCompletionRoutine(irp, &irpCompletion, 0, TRUE, TRUE, TRUE);
IoCallDriver(hookedDevice, irp);
KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);

return NT_SUCCESS(ioStatus.Status);
}

/*=======================================================================*/

BOOLEAN irpGetStandardInfo(
PDEVICE_OBJECT hookedDevice,
PFILE_OBJECT fileObject,
PFILE_STANDARD_INFORMATION standardInfo
)
{
DbgPrint((“direct IRP get standard information\n”));

return irpGetInfo(
hookedDevice,
fileObject,
standardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation
);
}

/*=======================================================================*/


You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Hi, Sara
Hi, xxxxx@trymedia.com

Thanks for your valuable advice!
I tried using the IRP_NOCACHE bit instead of the
IRP_SYNCHRONOUS_API bit and removed IoMarkIrpPending()
to no effect.

I added DbgPrint() as follows and I confirmed whenever the
lower redirector returned STATUS_PENDING, my completion
routine was not called.

NTSTATUS MyCompleteRoutine(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIRP,
IN PVOID pContext)
{
DbgPrint(“Completion IRP=%08x\n”, pIRP);

}

NTSTATUS NTAPI
MyGetFileSize(
IN PDEVICE_OBJECT pDeviceObject,
IN PFILE_OBJECT pFileObject,
OUT PLARGE_INTEGER pFileSize)
{

ntResult = IoCallDriver(pDeviceObject, pIRP);
if(ntResult == STATUS_PENDING){
DbgPrint(“STATUS_PENDING IRP=%08x\n”, pIRP);
ntResult = KeWaitForSingleObject();
}

}

I will settle for my ad hoc solution using
the IRP_SYNCHRONOUS_API bit.
Thanks again for your time and assistance,

Regards,

Takashi


You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com