Sending Own Irp to Lower driver from Filter.

Hi All,
I am creating my own Irp using IoBuildAsynchronousFsdRequest in my disk class filter driver with major function IRP_MJ_WRITE and pass that Irp down to the other disk, I get the disk pointer from IoGetDeviceObjectPointer function, I facing problems my code is this…
RtlInitUnicodeString (&DevObj,DEVOBJ);
FileObj1 = ExAllocatePool (NonPagedPool,sizeof (FILE_OBJECT));
DevObjPtr = ExAllocatePool (NonPagedPool, sizeof (DEVICE_OBJECT));
IoStatusBlock = ExAllocatePool (NonPagedPool, sizeof (IO_STATUS_BLOCK));
IoGetDeviceObjectPointer (&DevObj,
FILE_ALL_ACCESS,
&FileObj1,
&DevObjPtr);
HighestDevObjPtr = IoGetAttachedDeviceReference (DevObjPtr);
if (HighestDevObjPtr ){
TestBuffer = ExAllocatePool (NonPagedPool, 512);
if (TestBuffer){
//filling the Buffer…
OwnIrp = IoBuildAsynchronousFsdRequest (IRP_MJ_WRITE,
HighestDevObjPtr,
&TestBuffer,
512,
OwnIrpOffSet,
IoStatusBlock);
IoSetCompletionRoutine(OwnIrp, CompletionRoutine111,
(PVOID)NULL, TRUE, TRUE,TRUE);
OwnIrpStatus = IoCallDriver (HighestDevObjPtr,OwnIrp);
}
}
NTSTATUS CompletionRoutine111 (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,
IN PVOID Context){
PMDL mdl;

while (mdl = Irp->MdlAddress)
{
Irp->MdlAddress = mdl->Next;
DbgPrint(“Before MmUnlockPages (mdl) \n”);
MmUnlockPages (mdl);
DbgPrint(“After MmUnlockPages (mdl) \n”);
IoFreeMdl (mdl);
}
IoFreeIrp (Irp);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}

Thanks in Advance
Saleem.

> RtlInitUnicodeString (&DevObj,DEVOBJ);

FileObj1 = ExAllocatePool (NonPagedPool,sizeof (FILE_OBJECT));
DevObjPtr = ExAllocatePool (NonPagedPool, sizeof (DEVICE_OBJECT));

No need to allocate these 2. They are returned by IoGetDeviceObjectPointer.

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

ok Max I am not allocating the two pointers but still getting bosd with error IRQL NOT LESS OR EQUAL… can u suggest what is the problem?
Thanks in Advance
Saleem.

I’d guess that freeing the IRP before returning from your completion
routine with status_more_processing_required is the problem. Your nuking
the IRP then telling the IOmanager you still need to do some processing
on the operation. If I remember correctly, when your completion routine
returns status_more_processing_required, the thread that set the
completion routine must deal with the irp.

just a guess,

m.

xxxxx@yahoo.com wrote:

ok Max I am not allocating the two pointers but still getting bosd with error IRQL NOT LESS OR EQUAL… can u suggest what is the problem?
Thanks in Advance
Saleem.


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

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> I’d guess that freeing the IRP before returning from your completion

routine with status_more_processing_required is the problem.

No, it is OK.

the IRP then telling the IOmanager you still need to do some processing
on the operation.

No, you tell IO manager - “hands off this IRP, abort the completion processing
and return from IoCompleteRequest”.

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

Hello All,

This is my first posting on this list. Saleem I want to find out what fields do you copy from the original IRP to your created IRP. I have found a sample code that does the following to set the fields of the newly created our own IRP. Do comment on this.

PIrpLocal below is our newly created IRP and IoManagerIrp is the original IRP from I/O Manager.

void FillingIrpArguments(PIRP PIrpLocal,PIRP IoManagerIrp)
{
PIrpLocal->Type=IoManagerIrp->Type;
PIrpLocal->Size=IoManagerIrp->Size;

//PIrpLocal->MdlAddress;

PIrpLocal->Flags=IoManagerIrp->Flags;
PIrpLocal->ThreadListEntry=IoManagerIrp->ThreadListEntry;

PIrpLocal->IoStatus=IoManagerIrp->IoStatus;

PIrpLocal->RequestorMode=IoManagerIrp->RequestorMode;

PIrpLocal->PendingReturned=IoManagerIrp->PendingReturned;

PIrpLocal->StackCount=IoManagerIrp->StackCount;
PIrpLocal->CurrentLocation=IoManagerIrp->CurrentLocation;

PIrpLocal->Cancel=IoManagerIrp->Cancel;

PIrpLocal->CancelIrql=IoManagerIrp->CancelIrql;

PIrpLocal->ApcEnvironment=IoManagerIrp->ApcEnvironment;

PIrpLocal->AllocationFlags=IoManagerIrp->AllocationFlags;

}

Also do comment what will happen if we use the function IoAllocateIrp for allocating IRP instead of IoBuildAsynchronousFsdRequest function.

Also one more question what is the best forum for discussing the windows driver related problems.

Thanks,
Uzair Lakhani,
Karachi, Pakistan.

Just copy the following fields from
IoGetCurrentIrpStackLocation(IoManagerIrp) to
IoGetNextIrpStackLocation(PIrpLocal)

  1. The parameters union
  2. MajorFunction
  3. MinorFunction

Set RequestorMode to KernelMode in PIrpLocal.

Do not copy ThreadListEntry, PendingReturned, StackCOunt,
CurrentLocation, Cancel, CancelIrql, ApcEnvironment, or AllocationFlags.

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.com
Sent: Monday, September 04, 2006 9:45 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Sending Own Irp to Lower driver from Filter.

Hello All,

This is my first posting on this list. Saleem I want to find out what
fields do you copy from the original IRP to your created IRP. I have
found a sample code that does the following to set the fields of the
newly created our own IRP. Do comment on this.

PIrpLocal below is our newly created IRP and IoManagerIrp is the
original IRP from I/O Manager.

void FillingIrpArguments(PIRP PIrpLocal,PIRP IoManagerIrp)
{
PIrpLocal->Type=IoManagerIrp->Type;
PIrpLocal->Size=IoManagerIrp->Size;

//PIrpLocal->MdlAddress;

PIrpLocal->Flags=IoManagerIrp->Flags;

PIrpLocal->ThreadListEntry=IoManagerIrp->ThreadListEntry;

PIrpLocal->IoStatus=IoManagerIrp->IoStatus;

PIrpLocal->RequestorMode=IoManagerIrp->RequestorMode;

PIrpLocal->PendingReturned=IoManagerIrp->PendingReturned;

PIrpLocal->StackCount=IoManagerIrp->StackCount;

PIrpLocal->CurrentLocation=IoManagerIrp->CurrentLocation;

PIrpLocal->Cancel=IoManagerIrp->Cancel;

PIrpLocal->CancelIrql=IoManagerIrp->CancelIrql;

PIrpLocal->ApcEnvironment=IoManagerIrp->ApcEnvironment;

PIrpLocal->AllocationFlags=IoManagerIrp->AllocationFlags;

}

Also do comment what will happen if we use the function IoAllocateIrp
for allocating IRP instead of IoBuildAsynchronousFsdRequest function.

Also one more question what is the best forum for discussing the windows
driver related problems.

Thanks,
Uzair Lakhani,
Karachi, Pakistan.


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

>Also do comment what will happen if we use the function IoAllocateIrp
for >allocating IRP instead of IoBuildAsynchronousFsdRequest function.

IoBuildAsynchronousFsdRequest actually calls IoAllocateIrp in its
implementation. Besides it will also go on to initialize many of the
fields in the allocated Irp. For example, it will allocate MDL list and
set up system buffer based upon whether the driver want to use
BufferedIo or DirectIo.

I think it will be better to use the first one unless you can be sure
there is no memory transfer involved in the Irp processing.

Just my personal opinion for your reference.:wink:

Best regards,
Cody

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.com
Sent: Tuesday, September 05, 2006 12:45 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Sending Own Irp to Lower driver from Filter.

Hello All,

This is my first posting on this list. Saleem I want to find out what
fields do you copy from the original IRP to your created IRP. I have
found a sample code that does the following to set the fields of the
newly created our own IRP. Do comment on this.

PIrpLocal below is our newly created IRP and IoManagerIrp is the
original IRP from I/O Manager.

void FillingIrpArguments(PIRP PIrpLocal,PIRP IoManagerIrp)
{
PIrpLocal->Type=IoManagerIrp->Type;
PIrpLocal->Size=IoManagerIrp->Size;

//PIrpLocal->MdlAddress;

PIrpLocal->Flags=IoManagerIrp->Flags;

PIrpLocal->ThreadListEntry=IoManagerIrp->ThreadListEntry;

PIrpLocal->IoStatus=IoManagerIrp->IoStatus;

PIrpLocal->RequestorMode=IoManagerIrp->RequestorMode;

PIrpLocal->PendingReturned=IoManagerIrp->PendingReturned;

PIrpLocal->StackCount=IoManagerIrp->StackCount;

PIrpLocal->CurrentLocation=IoManagerIrp->CurrentLocation;

PIrpLocal->Cancel=IoManagerIrp->Cancel;

PIrpLocal->CancelIrql=IoManagerIrp->CancelIrql;

PIrpLocal->ApcEnvironment=IoManagerIrp->ApcEnvironment;

PIrpLocal->AllocationFlags=IoManagerIrp->AllocationFlags;

}

Also do comment what will happen if we use the function IoAllocateIrp
for allocating IRP instead of IoBuildAsynchronousFsdRequest function.

Also one more question what is the best forum for discussing the windows
driver related problems.

Thanks,
Uzair Lakhani,
Karachi, Pakistan.


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

> PIrpLocal->Type=IoManagerIrp->Type;

PIrpLocal->Size=IoManagerIrp->Size;

Filled by IoAllocateIrp

PIrpLocal->Flags=IoManagerIrp->Flags;
PIrpLocal->ThreadListEntry=IoManagerIrp->ThreadListEntry;

Do not touch these. ->ThreadListEntry is only filled in IO manager-generated
IRPs.

PIrpLocal->IoStatus=IoManagerIrp->IoStatus;

No need. You fill IoStatus yourself just before IoCompleteRequest.

PIrpLocal->RequestorMode=IoManagerIrp->RequestorMode;

->RequestorMode is UserMode only if the buffer described by the IRP is the user
buffer. If it is, say, system buffer, or the partial MDL - then set to
KernelMode.

PIrpLocal->PendingReturned=IoManagerIrp->PendingReturned;

Never fill it. IoAllocateIrp fills this properly, and the field is only updated
in completion path.

PIrpLocal->StackCount=IoManagerIrp->StackCount;
PIrpLocal->CurrentLocation=IoManagerIrp->CurrentLocation;

Again filled by IoAllocateIrp.

PIrpLocal->Cancel=IoManagerIrp->Cancel;
PIrpLocal->CancelIrql=IoManagerIrp->CancelIrql;

Filled by IoAllocateIrp, then only updated if somebody is cancelling the IRP.

PIrpLocal->ApcEnvironment=IoManagerIrp->ApcEnvironment;
PIrpLocal->AllocationFlags=IoManagerIrp->AllocationFlags;

Again filled by IoAllocateIrp. Do not touch these fields.

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

>Just copy the following fields from

IoGetCurrentIrpStackLocation(IoManagerIrp) to
IoGetNextIrpStackLocation(PIrpLocal)

  1. The parameters union
  2. MajorFunction
  3. MinorFunction

For disk stack IRPs, also ->Tail.Overlay.Thread must be set, and to a valid
thread.

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

Ahh, That’s right. I’ve pretty much been removed from IRP handlin’ with
mini filters for the last year.

M$ could of picked a better name for IoFreeIrp - that has always always
confused me. Every time
I see that function, I think it’s deallocating the memory for the IRP…

On the bright side, I’ll never forget this again after my self inflicted
burn (again)…

m.

Maxim S. Shatskih wrote:

>I’d guess that freeing the IRP before returning from your completion
>routine with status_more_processing_required is the problem.
>
>

No, it is OK.

>the IRP then telling the IOmanager you still need to do some processing
>on the operation.
>
>

No, you tell IO manager - “hands off this IRP, abort the completion processing
and return from IoCompleteRequest”.

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


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

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> M$ could of picked a better name for IoFreeIrp - that has always always

confused me. Every time
I see that function, I think it’s deallocating the memory for the IRP…

IoFreeIrp really frees the IRP’s memory.

STATUS_MORE_PROCESSING_REQUIRED is not a good name - STATUS_ABORT_COMPLETION
would be better.

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

Maxim S. Shatskih wrote:

>M$ could of picked a better name for IoFreeIrp - that has always always
>confused me. Every time
>I see that function, I think it’s deallocating the memory for the IRP…
>
>

IoFreeIrp really frees the IRP’s memory.

STATUS_MORE_PROCESSING_REQUIRED is not a good name - STATUS_ABORT_COMPLETION
would be better.

But “abort” implies an abnormal termination, which this is not.
STATUS_STOP_PROCESSING_IRP or STATUS_IRP_FINISHED might express the
sentiment better.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Ok, I’ve love if someone could explain this too me.

I originally thought that calling IoFreeIrp before returning from a
completion routine with
STATUS_MORE_PROCESSING_REQUIRED would cause an error. It was originally my
contention:

“I’d guess that freeing the IRP before returning from your completion
routine with status_more_processing_required
is the problem. Your nuking the IRP then telling the IOmanager you still
need to do some processing on the operation.”

Max said this is OK, so I assumed I misunderstood what IoFreeIrp does.
I looked to the ddk and read this:

“The *IoFreeIrp* routine releases a caller-allocated IRP from the
caller’s /IoCompletion/ routine.”. I then looked too
the samples and saw that they all call IoFreeIrp before returning
STATUS_MORE_PROCESSING_REQUIRED.

Max also indicated that when you do a IoFreeIrp followed by
STATUS_MORE_PROCESSING_REQUIRED
your telling the IO manager:

“you tell IO manager - “hands off this IRP, abort the completion processing
and return from IoCompleteRequest”.”.

Tim then chimed in with: “STATUS_STOP_PROCESSING_IRP or STATUS_IRP_FINISHED might
express the sentiment better.”

Max also reinforced my ‘original’ veiw that IoFreeIrp deallocated memory for the IRP by
stating: “IoFreeIrp really frees the IRP’s memory.”

So what’s happening here? In the completion routine you free the IRP and release all
memory associated with it. Then, you tell the IO manager to stop processing the IRP
(which no longer exist because you just freed it). Why is this not dangerous? How can
you tell the Io Manager to stop processing something you just destroyed; shouldn’t there
be a crap load of bad pointers now, all referencing bad memory?

Just curious here,

m.

Maxim S. Shatskih wrote:

>M$ could of picked a better name for IoFreeIrp - that has always always
>confused me. Every time
>I see that function, I think it’s deallocating the memory for the IRP…
>
>

IoFreeIrp really frees the IRP’s memory.

STATUS_MORE_PROCESSING_REQUIRED is not a good name - STATUS_ABORT_COMPLETION
would be better.

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


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

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

MM дµÀ:

So what’s happening here? In the completion routine you free the IRP and
release all memory associated with it. Then, you tell the IO manager to
stop processing the IRP
(which no longer exist because you just freed it). Why is this not
dangerous? How can you tell the Io Manager to stop processing something
you just destroyed; shouldn’t there
be a crap load of bad pointers now, all referencing bad memory?

IO Manager never touches the irp any more if the completion routine
returns STATUS_MORE_PROCESSING_REQUIRED. If you doesn’t access it, no
one would touch it. So it’s safe. :slight_smile:

Just curious here,

m.

Maxim S. Shatskih wrote:

>> M$ could of picked a better name for IoFreeIrp - that has always always
>> confused me. Every time
>> I see that function, I think it’s deallocating the memory for the
>> IRP…
>>
>
> IoFreeIrp really frees the IRP’s memory.
>
> STATUS_MORE_PROCESSING_REQUIRED is not a good name -
> STATUS_ABORT_COMPLETION
> would be better.
>
> Maxim Shatskih, Windows DDK MVP
> StorageCraft Corporation
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
>
>


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

If you allocated your own IRP, then submitted to a lower device, and your completion routine was called, then yes, you SHOULD call IoFreeIrp and then return STATUS_MORE_PROCESSING_REQUIRED.

It’s not dangerous because IoCompleteRequest was designed for just this scenario. When a driver calls IoCompleteRequest, the I/O manager starts walking the list of I/O stack locations, looking for completion routines, and it calls those completion routines. Each time it does so, it moves the current I/O stack location pointer. If any of those routines returns STATUS_MORE_PROCESSING_REQUIRED, then IoCompleteRequest *immediately* returns, without touching any more IRP fields, because the IRP may have already been deleted.

If you do a thought-experiment, you’ll see that IoCompleteRequest *must* work this way. Consider the classical meaning of STATUS_MORE_PROCESSING_REQUIRED, where a completion routine realizes that it needs to do more work on the current IRP before it can allow the IRP completion to continue. (As a hypothetical case, maybe the driver processing the IRP is working on segmenting a large transfer into many smaller ones, and the current IRP completion was not the last segment transferred, so the driver re-submits the IRP to the lower layer.) If the completion routine re-submits that IRP, then the lower driver could process that IRP, and call IoCompleteRequest on a different processor. That second instance of the completion routine could free the IRP and return STATUS_MORE_PROCESSING_REQUIRED, or if it was an IRP received on a dispatch function and not allocated using IoAllocateIrp, it could just return STATUS_SUCCESS. At this point, the IRP has been destroyed, so the first instance of the completion routine, including the code in IoCompleteRequest, *must not* touch the IRP.

This behavior is guaranteed. If you allocate your own IRP, using IoAllocateIrp, and submit it to a lower driver, then you should free it in your completion routine and should return STATUS_MORE_PROCESSING_REQUIRED. This is safe, supported behavior.

Nota bene: If you are doing this, then you need to be aware of a certain race condition that can occur during shutdown. Your driver can be unloaded while your completion routine is running, because the OS has not incremented the reference count on your PDEVICE_OBJECT or your PDRIVER_OBJECT. So if you are using this design pattern, you must use IoSetCompletionRoutineEx, instead of IoSetCompletionRoutine. And because IoSetCompletionRoutineEx can fail (because it necessarily allocates memory), you must check its return value.

– arlie

P.S. Please restrict use of “M$” to sycophantic fan-boy posts on Slashdot. It’s childish.

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of MM
Sent: Wednesday, September 06, 2006 4:30 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Sending Own Irp to Lower driver from Filter.

Ok, I’ve love if someone could explain this too me.

I originally thought that calling IoFreeIrp before returning from a completion routine with STATUS_MORE_PROCESSING_REQUIRED would cause an error. It was originally my
contention:

“I’d guess that freeing the IRP before returning from your completion routine with status_more_processing_required is the problem. Your nuking the IRP then telling the IOmanager you still need to do some processing on the operation.”

Max said this is OK, so I assumed I misunderstood what IoFreeIrp does.
I looked to the ddk and read this:

“The *IoFreeIrp* routine releases a caller-allocated IRP from the caller’s /IoCompletion/ routine.”. I then looked too the samples and saw that they all call IoFreeIrp before returning STATUS_MORE_PROCESSING_REQUIRED.

Max also indicated that when you do a IoFreeIrp followed by STATUS_MORE_PROCESSING_REQUIRED your telling the IO manager:

“you tell IO manager - “hands off this IRP, abort the completion processing and return from IoCompleteRequest”.”.

Tim then chimed in with: “STATUS_STOP_PROCESSING_IRP or STATUS_IRP_FINISHED might express the sentiment better.”

Max also reinforced my ‘original’ veiw that IoFreeIrp deallocated memory for the IRP by
stating: “IoFreeIrp really frees the IRP’s memory.”

So what’s happening here? In the completion routine you free the IRP and release all memory associated with it. Then, you tell the IO manager to stop processing the IRP (which no longer exist because you just freed it). Why is this not dangerous? How can you tell the Io Manager to stop processing something you just destroyed; shouldn’t there be a crap load of bad pointers now, all referencing bad memory?

Just curious here,

m.

Maxim S. Shatskih wrote:

>M$ could of picked a better name for IoFreeIrp - that has always
>always confused me. Every time I see that function, I think it’s
>deallocating the memory for the IRP…
>
>

IoFreeIrp really frees the IRP’s memory.

STATUS_MORE_PROCESSING_REQUIRED is not a good name -
STATUS_ABORT_COMPLETION would be better.

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


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


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

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

I wrote about both (rolling your own irps, unload synchronization) if
you care to read about it

Threaded irps:
http://blogs.msdn.com/doronh/archive/2006/07/27/681179.aspx
IoSetCompletionRoutineEx:
http://blogs.msdn.com/doronh/archive/2006/08/08/692479.aspx

d

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Arlie Davis
Sent: Wednesday, September 06, 2006 9:00 AM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Sending Own Irp to Lower driver from Filter.

If you allocated your own IRP, then submitted to a lower device, and
your completion routine was called, then yes, you SHOULD call IoFreeIrp
and then return STATUS_MORE_PROCESSING_REQUIRED.

It’s not dangerous because IoCompleteRequest was designed for just this
scenario. When a driver calls IoCompleteRequest, the I/O manager starts
walking the list of I/O stack locations, looking for completion
routines, and it calls those completion routines. Each time it does so,
it moves the current I/O stack location pointer. If any of those
routines returns STATUS_MORE_PROCESSING_REQUIRED, then IoCompleteRequest
*immediately* returns, without touching any more IRP fields, because the
IRP may have already been deleted.

If you do a thought-experiment, you’ll see that IoCompleteRequest *must*
work this way. Consider the classical meaning of
STATUS_MORE_PROCESSING_REQUIRED, where a completion routine realizes
that it needs to do more work on the current IRP before it can allow the
IRP completion to continue. (As a hypothetical case, maybe the driver
processing the IRP is working on segmenting a large transfer into many
smaller ones, and the current IRP completion was not the last segment
transferred, so the driver re-submits the IRP to the lower layer.) If
the completion routine re-submits that IRP, then the lower driver could
process that IRP, and call IoCompleteRequest on a different processor.
That second instance of the completion routine could free the IRP and
return STATUS_MORE_PROCESSING_REQUIRED, or if it was an IRP received on
a dispatch function and not allocated using IoAllocateIrp, it could just
return STATUS_SUCCESS. At this point, the IRP has been destroyed, so
the first instance of the completion routine, including the code in
IoCompleteRequest, *must not* touch the IRP.

This behavior is guaranteed. If you allocate your own IRP, using
IoAllocateIrp, and submit it to a lower driver, then you should free it
in your completion routine and should return
STATUS_MORE_PROCESSING_REQUIRED. This is safe, supported behavior.

Nota bene: If you are doing this, then you need to be aware of a certain
race condition that can occur during shutdown. Your driver can be
unloaded while your completion routine is running, because the OS has
not incremented the reference count on your PDEVICE_OBJECT or your
PDRIVER_OBJECT. So if you are using this design pattern, you must use
IoSetCompletionRoutineEx, instead of IoSetCompletionRoutine. And
because IoSetCompletionRoutineEx can fail (because it necessarily
allocates memory), you must check its return value.

– arlie

P.S. Please restrict use of “M$” to sycophantic fan-boy posts on
Slashdot. It’s childish.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of MM
Sent: Wednesday, September 06, 2006 4:30 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Sending Own Irp to Lower driver from Filter.

Ok, I’ve love if someone could explain this too me.

I originally thought that calling IoFreeIrp before returning from a
completion routine with STATUS_MORE_PROCESSING_REQUIRED would cause an
error. It was originally my
contention:

“I’d guess that freeing the IRP before returning from your completion
routine with status_more_processing_required is the problem. Your nuking
the IRP then telling the IOmanager you still need to do some processing
on the operation.”

Max said this is OK, so I assumed I misunderstood what IoFreeIrp does.
I looked to the ddk and read this:

“The *IoFreeIrp* routine releases a caller-allocated IRP from the
caller’s /IoCompletion/ routine.”. I then looked too the samples and saw
that they all call IoFreeIrp before returning
STATUS_MORE_PROCESSING_REQUIRED.

Max also indicated that when you do a IoFreeIrp followed by
STATUS_MORE_PROCESSING_REQUIRED your telling the IO manager:

“you tell IO manager - “hands off this IRP, abort the completion
processing and return from IoCompleteRequest”.”.

Tim then chimed in with: “STATUS_STOP_PROCESSING_IRP or
STATUS_IRP_FINISHED might express the sentiment better.”

Max also reinforced my ‘original’ veiw that IoFreeIrp deallocated memory
for the IRP by
stating: “IoFreeIrp really frees the IRP’s memory.”

So what’s happening here? In the completion routine you free the IRP and
release all memory associated with it. Then, you tell the IO manager to
stop processing the IRP (which no longer exist because you just freed
it). Why is this not dangerous? How can you tell the Io Manager to stop
processing something you just destroyed; shouldn’t there be a crap load
of bad pointers now, all referencing bad memory?

Just curious here,

m.

Maxim S. Shatskih wrote:

>M$ could of picked a better name for IoFreeIrp - that has always
>always confused me. Every time I see that function, I think it’s
>deallocating the memory for the IRP…
>
>

IoFreeIrp really frees the IRP’s memory.

STATUS_MORE_PROCESSING_REQUIRED is not a good name -
STATUS_ABORT_COMPLETION would be better.

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


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

> So what’s happening here? In the completion routine you free the IRP and

release all
memory associated with it. Then, you tell the IO manager to stop processing
the
IRP
(which no longer exist because you just freed it). Why is this not dangerous?

After getting STATUS_MORE_PROCESSING_REQUIRED from the completion routine in
one of the stack locations, IoCompleteRequest immediately returns to its
caller, and no more touches the IRP.

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

I think some confusion could be avoided if the return code didn’t sound
like more processing would be done on the IRP you just freed. Maybe
STATUS_DONT_TOUCH_THIS _IRP_ANYMORE (or something a little more elegant)
would be more appropriate. In fact STATUS_NO_MORE_PROCESSING would
provide a more intuitive feel for what it is actually doing in this
case. To say MORE_PROCESSING REQUIRED just “feels” wrong because it
implies that the IRP will be processed some more.

Beverly

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Wednesday, September 06, 2006 1:20 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Sending Own Irp to Lower driver from Filter.

So what’s happening here? In the completion routine you free the IRP
and release all memory associated with it. Then, you tell the IO
manager to stop processing
the
IRP
(which no longer exist because you just freed it). Why is this not
dangerous?

After getting STATUS_MORE_PROCESSING_REQUIRED from the completion
routine in one of the stack locations, IoCompleteRequest immediately
returns to its caller, and no more touches the IRP.

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


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

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Arlie and others,

Thanks for the detailed post(s). As several people pointed out, the name
of the return status is confusing. To further confuse me,
on pages 164-165 of Nagar’s book, it states, “If any completion routine
returns STATUS_MORE_PROCESSING_REQUIRED, the I/O
Manager immediately stops all further post processing and returns
control back to the routine that invoked IoCompleteRequest(). Now, it
is the responsibility of the driver that returned
STATUS_MORE_PROCESSING_REQUIRED to invoke IoFreeIrp() later.”

That quote stuck in my mind, giving me the idea that you must free the
IRP later *after* returning more_processing_required. From the way
I interpreted it, the above quote gave me the impression that the IO
manager could touch a freed IRP thus resulting in an unsafe condition if
you returned more_processing_required after freeing the IRP.

Thanks for the clarification,

m.