When to call IoFreeMdl while allocating IRP using IoBuildAsynchronousFsdRequest

Hi All,

I am a newbie to driver development. I was going through some sample code
given in DDK. I found that in many cases we are allocating an IRP with
IoBuildAsynchronousFsdRequest and then in Completion routine we call
MmUnlock and IoFreeMdl before calling IoFreeIrp. But in many cases it
simply calls IoFreeIrp and returns.

Can someone explain to me in what cases we need to Free the MDL and when
not to free the MDL.

Thanks
Brian

If an MDL was created for the IRP by the diver you are calling you need to
free it before freeing IRP.
Some requests, for example IOCTL defined as METHOD_BUFFERED never produce an
MDL.

Alexei.

“Brain” wrote in message news:xxxxx@ntfsd…
>
> Hi All,
>
> I am a newbie to driver development. I was going through some sample code
> given in DDK. I found that in many cases we are allocating an IRP with
> IoBuildAsynchronousFsdRequest and then in Completion routine we call
> MmUnlock and IoFreeMdl before calling IoFreeIrp. But in many cases it
> simply calls IoFreeIrp and returns.
>
> Can someone explain to me in what cases we need to Free the MDL and when
> not to free the MDL.
>
> Thanks
> Brian
>
>

I got what you are saying but in many cases i saw that we are not
allocating MDLs explicitely but still we are freeing it. Here are two
cases

********** From Serial.C in DDK samples.
irp = IoBuildAsynchronousFsdRequest(fRead? IRP_MJ_READ: IRP_MJ_WRITE,
DevExt->LowerDevObj,
Buffer,
BuffLen,
&StartingOffset,
NULL);
if (irp != NULL)
{
status = IoAcquireRemoveLock(&DevExt->RemoveLock, irp);
if (NT_SUCCESS(status))
{
IoSetCompletionRoutine(irp,
AsyncReadWriteCompletion,
DevExt,
TRUE,
TRUE,
TRUE);

******** Completion Routine *******
NTSTATUS INTERNAL
AsyncReadWriteCompletion(
IN PDEVICE_OBJECT DevObj,
IN PIRP Irp,
IN PDEVICE_EXTENSION DevExt
)
{
TRACEPROC(“AsyncReadWriteCompletion”, 2)
NTSTATUS status = Irp->IoStatus.Status;

TRACEENTER((“(DevObj=%p,Irp=%p,devext=%p,Status=%x)\n”,
DevObj, Irp, DevExt, status));

if (status == STATUS_CANCELLED)
{
TRACEWARN((“AsyncReadWrite IRP was cancelled.\n”));
}
else if (!NT_SUCCESS(status))
{
TRACEWARN((“AsyncReadWrite irp failed (status=%x).\n”, status));
}

IoReleaseRemoveLock(&DevExt->RemoveLock, Irp);
IoFreeIrp(Irp);
status = STATUS_MORE_PROCESSING_REQUIRED;

TRACEEXIT((“=%x\n”, status));
return status;
} //AsyncReadWriteCompletion
********************************************

In this case I dont see any IoFreeMdl getting called. The buffer here was
not allocated using any MDL function. where as in the other example.

************** From Verfysup.C in DDK samples. ************

Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
Vcb->TargetDeviceObject,
(PVOID)Sector,
WriteLength,
&Offset,
NULL );

if ( Irp == NULL ) {

try_return(NOTHING);
}

//
// Make this operation write-through. It never hurts to try
to be
// safer about this, even though we aren’t logged.
//

SetFlag( IoGetNextIrpStackLocation( Irp )->Flags,
SL_WRITE_THROUGH );

//
// Set up the completion routine
//

IoSetCompletionRoutine( Irp,
FatMarkVolumeCompletionRoutine,
&Event,
TRUE,
TRUE,
TRUE );



// Clean up the Irp and Mdl
//

if (Irp) {

//
// If there is an MDL (or MDLs) associated with this I/O
// request, Free it (them) here. This is accomplished by
// walking the MDL list hanging off of the IRP and
deallocating
// each MDL encountered.
//

while (Irp->MdlAddress != NULL) {

PMDL NextMdl;

NextMdl = Irp->MdlAddress->Next;

MmUnlockPages( Irp->MdlAddress );

IoFreeMdl( Irp->MdlAddress );

Irp->MdlAddress = NextMdl;
}

IoFreeIrp( Irp );
}
********* Completion routine **********

NTSTATUS
FatMarkVolumeCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Contxt
)

{
//
// Set the event so that our call will wake up.
//

KeSetEvent( (PKEVENT)Contxt, 0, FALSE );

UNREFERENCED_PARAMETER( DeviceObject );
UNREFERENCED_PARAMETER( Irp );

return STATUS_MORE_PROCESSING_REQUIRED;
}

**********************************************
In this case the buffer, “sector” was the return value from CcPinRead(…).

Can someone explain why its different in these two places.

Thanks
Brain

If you return STATUS_SUCCESS from the completion, thus passing the
completely unwound IRP back to IO manager, then you must not unlock and free
Irp->MdlAddress, since it is done by IO manager after calling all completion
routines.

Max

----- Original Message -----
From: “Brain”
To: “File Systems Developers”
Sent: Thursday, July 17, 2003 1:44 AM
Subject: [ntfsd] When to call IoFreeMdl while allocating IRP using
IoBuildAsynchronousFsdRequest

> Hi All,
>
> I am a newbie to driver development. I was going through some sample code
> given in DDK. I found that in many cases we are allocating an IRP with
> IoBuildAsynchronousFsdRequest and then in Completion routine we call
> MmUnlock and IoFreeMdl before calling IoFreeIrp. But in many cases it
> simply calls IoFreeIrp and returns.
>
> Can someone explain to me in what cases we need to Free the MDL and when
> not to free the MDL.
>
> Thanks
> Brian
>
> —
> You are currently subscribed to ntfsd as: xxxxx@storagecraft.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

I ment that if a driver BELOW you allocated an MDL you have to free it, like
in FAT example.
If the device has flag DO_BUFFERED_IO like device created by serial port
driver data is returned in irp->AssosiatedIrp.SystemBuffer and no MDL is
generated.

Alexei.

“Brain” wrote in message news:xxxxx@ntfsd…
>
> I got what you are saying but in many cases i saw that we are not
> allocating MDLs explicitely but still we are freeing it. Here are two
> cases
>
> **From Serial.C in DDK samples.
> irp = IoBuildAsynchronousFsdRequest(fRead? IRP_MJ_READ: IRP_MJ_WRITE,
> DevExt->LowerDevObj,
> Buffer,
> BuffLen,
> &StartingOffset,
> NULL);
> if (irp != NULL)
> {
> status = IoAcquireRemoveLock(&DevExt->RemoveLock, irp);
> if (NT_SUCCESS(status))
> {
> IoSetCompletionRoutine(irp,
> AsyncReadWriteCompletion,
> DevExt,
> TRUE,
> TRUE,
> TRUE);
>
>
Completion Routine *******
> NTSTATUS INTERNAL
> AsyncReadWriteCompletion(
> IN PDEVICE_OBJECT DevObj,
> IN PIRP Irp,
> IN PDEVICE_EXTENSION DevExt
> )
> {
> TRACEPROC(“AsyncReadWriteCompletion”, 2)
> NTSTATUS status = Irp->IoStatus.Status;
>
> TRACEENTER((“(DevObj=%p,Irp=%p,devext=%p,Status=%x)\n”,
> DevObj, Irp, DevExt, status));
>
> if (status == STATUS_CANCELLED)
> {
> TRACEWARN((“AsyncReadWrite IRP was cancelled.\n”));
> }
> else if (!NT_SUCCESS(status))
> {
> TRACEWARN((“AsyncReadWrite irp failed (status=%x).\n”, status));
> }
>
> IoReleaseRemoveLock(&DevExt->RemoveLock, Irp);
> IoFreeIrp(Irp);
> status = STATUS_MORE_PROCESSING_REQUIRED;
>
> TRACEEXIT((“=%x\n”, status));
> return status;
> } //AsyncReadWriteCompletion
>********************************************
>
> In this case I dont see any IoFreeMdl getting called. The buffer here was
> not allocated using any MDL function. where as in the other example.
>
> *From Verfysup.C in DDK samples.
>
> Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
> Vcb->TargetDeviceObject,
> (PVOID)Sector,
> WriteLength,
> &Offset,
> NULL );
>
> if ( Irp == NULL ) {
>
> try_return(NOTHING);
> }
>
> //
> // Make this operation write-through. It never hurts to try
> to be
> // safer about this, even though we aren’t logged.
> //
>
> SetFlag( IoGetNextIrpStackLocation( Irp )->Flags,
> SL_WRITE_THROUGH );
>
> //
> // Set up the completion routine
> //
>
> IoSetCompletionRoutine( Irp,
> FatMarkVolumeCompletionRoutine,
> &Event,
> TRUE,
> TRUE,
> TRUE );
> …
> …
> …
> // Clean up the Irp and Mdl
> //
>
> if (Irp) {
>
> //
> // If there is an MDL (or MDLs) associated with this I/O
> // request, Free it (them) here. This is accomplished by
> // walking the MDL list hanging off of the IRP and
> deallocating
> // each MDL encountered.
> //
>
> while (Irp->MdlAddress != NULL) {
>
> PMDL NextMdl;
>
> NextMdl = Irp->MdlAddress->Next;
>
> MmUnlockPages( Irp->MdlAddress );
>
> IoFreeMdl( Irp->MdlAddress );
>
> Irp->MdlAddress = NextMdl;
> }
>
> IoFreeIrp( Irp );
> }
> Completion routine

>
> NTSTATUS
> FatMarkVolumeCompletionRoutine(
> IN PDEVICE_OBJECT DeviceObject,
> IN PIRP Irp,
> IN PVOID Contxt
> )
>
> {
> //
> // Set the event so that our call will wake up.
> //
>
> KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
>
> UNREFERENCED_PARAMETER( DeviceObject );
> UNREFERENCED_PARAMETER( Irp );
>
> return STATUS_MORE_PROCESSING_REQUIRED;
> }
>
> **********************************************
> In this case the buffer, “sector” was the return value from CcPinRead(…).
>
> Can someone explain why its different in these two places.
>
> Thanks
> Brain
>
>

Actually if the DEVICE_OBJECT passed into IoBuildAsynchronousFsdRequest has
DO_DIRECT_IO flag then MDL is created by the function itself, not by
underlying driver.
Anyway, if there is an MDL defined for the IRP you are responsible to free
it. If you know for sure that no MDL is generated you can skip code that
frees MDL.

Alexei.

“Alexei Jelvis” wrote in message news:xxxxx@ntfsd…
>
> I ment that if a driver BELOW you allocated an MDL you have to free it,
like
> in FAT example.
> If the device has flag DO_BUFFERED_IO like device created by serial port
> driver data is returned in irp->AssosiatedIrp.SystemBuffer and no MDL is
> generated.
>
> Alexei.
>
> “Brain” wrote in message news:xxxxx@ntfsd…
> >
> > I got what you are saying but in many cases i saw that we are not
> > allocating MDLs explicitely but still we are freeing it. Here are two
> > cases
> >
> > **From Serial.C in DDK samples.
> > irp = IoBuildAsynchronousFsdRequest(fRead? IRP_MJ_READ: IRP_MJ_WRITE,
> > DevExt->LowerDevObj,
> > Buffer,
> > BuffLen,
> > &StartingOffset,
> > NULL);
> > if (irp != NULL)
> > {
> > status = IoAcquireRemoveLock(&DevExt->RemoveLock, irp);
> > if (NT_SUCCESS(status))
> > {
> > IoSetCompletionRoutine(irp,
> > AsyncReadWriteCompletion,
> > DevExt,
> > TRUE,
> > TRUE,
> > TRUE);
> >
> >
Completion Routine *******
> > NTSTATUS INTERNAL
> > AsyncReadWriteCompletion(
> > IN PDEVICE_OBJECT DevObj,
> > IN PIRP Irp,
> > IN PDEVICE_EXTENSION DevExt
> > )
> > {
> > TRACEPROC(“AsyncReadWriteCompletion”, 2)
> > NTSTATUS status = Irp->IoStatus.Status;
> >
> > TRACEENTER((“(DevObj=%p,Irp=%p,devext=%p,Status=%x)\n”,
> > DevObj, Irp, DevExt, status));
> >
> > if (status == STATUS_CANCELLED)
> > {
> > TRACEWARN((“AsyncReadWrite IRP was cancelled.\n”));
> > }
> > else if (!NT_SUCCESS(status))
> > {
> > TRACEWARN((“AsyncReadWrite irp failed (status=%x).\n”, status));
> > }
> >
> > IoReleaseRemoveLock(&DevExt->RemoveLock, Irp);
> > IoFreeIrp(Irp);
> > status = STATUS_MORE_PROCESSING_REQUIRED;
> >
> > TRACEEXIT((“=%x\n”, status));
> > return status;
> > } //AsyncReadWriteCompletion
> >********************************************
> >
> > In this case I dont see any IoFreeMdl getting called. The buffer here
was
> > not allocated using any MDL function. where as in the other example.
> >
> > *From Verfysup.C in DDK samples.
> >
> > Irp = IoBuildAsynchronousFsdRequest( IRP_MJ_WRITE,
> >
Vcb->TargetDeviceObject,
> > (PVOID)Sector,
> > WriteLength,
> > &Offset,
> > NULL );
> >
> > if ( Irp == NULL ) {
> >
> > try_return(NOTHING);
> > }
> >
> > //
> > // Make this operation write-through. It never hurts to
try
> > to be
> > // safer about this, even though we aren’t logged.
> > //
> >
> > SetFlag( IoGetNextIrpStackLocation( Irp )->Flags,
> > SL_WRITE_THROUGH );
> >
> > //
> > // Set up the completion routine
> > //
> >
> > IoSetCompletionRoutine( Irp,
> > FatMarkVolumeCompletionRoutine,
> > &Event,
> > TRUE,
> > TRUE,
> > TRUE );
> > …
> > …
> > …
> > // Clean up the Irp and Mdl
> > //
> >
> > if (Irp) {
> >
> > //
> > // If there is an MDL (or MDLs) associated with this
I/O
> > // request, Free it (them) here. This is accomplished
by
> > // walking the MDL list hanging off of the IRP and
> > deallocating
> > // each MDL encountered.
> > //
> >
> > while (Irp->MdlAddress != NULL) {
> >
> > PMDL NextMdl;
> >
> > NextMdl = Irp->MdlAddress->Next;
> >
> > MmUnlockPages( Irp->MdlAddress );
> >
> > IoFreeMdl( Irp->MdlAddress );
> >
> > Irp->MdlAddress = NextMdl;
> > }
> >
> > IoFreeIrp( Irp );
> > }
> > Completion routine

> >
> > NTSTATUS
> > FatMarkVolumeCompletionRoutine(
> > IN PDEVICE_OBJECT DeviceObject,
> > IN PIRP Irp,
> > IN PVOID Contxt
> > )
> >
> > {
> > //
> > // Set the event so that our call will wake up.
> > //
> >
> > KeSetEvent( (PKEVENT)Contxt, 0, FALSE );
> >
> > UNREFERENCED_PARAMETER( DeviceObject );
> > UNREFERENCED_PARAMETER( Irp );
> >
> > return STATUS_MORE_PROCESSING_REQUIRED;
> > }
> >
> > **********************************************
> > In this case the buffer, “sector” was the return value from
CcPinRead(…).
> >
> > Can someone explain why its different in these two places.
> >
> > Thanks
> > Brain
> >
> >
>
>
>
>