Problem with using IoBuildAsynchronousFSDRequest

I am writing an FSD. I need a routine to read (contiguous sector aligned) data off the disk, so I rolled a function using IoBuildSynchronousFSDRequest. However, my routine needs to be able to work at APC_LEVEL, so I decided to replace it with IoBuildAsynchronousFSDRequest. Since the read disk function needs to be synchronous, I simply passed in a (pointer to) KEVENT type object (which was originally an argument to the IoBuildSynchrounous…) as the context to the completion routine, and signal it in the completion routine. However, this does not seem to work - while the first function using IoBuildSynchronousFSDRequest always completes successfully, the second one, after waiting, invariably returns STATUS_BUFFER_TOO_SMALL( -1073741789 = C0000023). I can’t fathom why. I have attached the code below, any suggestions?
Sorry for the length of this query.

/********* TECHNIQUE 1: Use of IoBuildSynchronousFSDRequest ******/
NTSTATUS ReadDisk(IN P_VCB PtrVCB,IN ULONGLONG Offset, IN ULONG Size, IN PVOID Buffer, IO_STATUS_BLOCK IoStatusBlock)
{
PIRP PtrIrp = NULL;
NTSTATUS RetCode = STATUS_SUCCESS;
LARGE_INTEGER DiskOffset;
KEVENT Event;
DiskOffset.QuadPart = Offset;

KeInitializeEvent(&Event,NotificationEvent,FALSE);

ASSERT(PtrVCB->TargetDeviceObject);
PtrIrp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
PtrVCB->TargetDeviceObject,
Buffer,
Size,
&DiskOffset,
&Event,
&IoStatusBlock);
ASSERT(PtrIrp);
if(!PtrIrp) {
RetCode = STATUS_INSUFFICIENT_RESOURCES;
return (RetCode);

}
RetCode = IoCallDriver(PtrVCB->TargetDeviceObject,PtrIrp);

if (RetCode == STATUS_PENDING) {
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
RetCode = IoStatusBlock.Status;
}
return RetCode;
}

/*****************************************************************************/

/********* TECHNIQUE 2: Use of IoBuildAsynchronousFSDRequest ******/

NTSTATUS ReadDiskCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PVOID Context
)
{
PKEVENT Event = NULL;

Event = (PKEVENT) Context;

/* signal the waiting ReadDisk to continue */
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);

/* Free the Irp */
IoFreeIrp(Irp);

/* Return STATUS_MORE_PROCESSING_REQUIRED. This must always be returned for Asynchronous Irps */
return STATUS_MORE_PROCESSING_REQUIRED;

}

NTSTATUS ReadDisk(IN P_VCB PtrVCB,IN ULONGLONG Offset, IN ULONG Size, IN PVOID Buffer, IO_STATUS_BLOCK IoStatusBlock)
{
PIRP PtrIrp = NULL;
NTSTATUS RetCode = STATUS_SUCCESS;
LARGE_INTEGER DiskOffset;
KEVENT *Event = NULL;

DiskOffset.QuadPart = Offset;
Event = (KEVENT *) ExAllocatePoolWithTag(NonPagedPool,sizeof(KEVENT),‘TEVE’);
if(!Event) {
RetCode = STATUS_INSUFFICIENT_RESOURCES;
return (RetCode);
}

KeInitializeEvent(Event,NotificationEvent,FALSE);

ASSERT(PtrVCB->TargetDeviceObject);
PtrIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ,
PtrVCB->TargetDeviceObject,
Buffer,
Size,
&DiskOffset,
&IoStatusBlock);

if(!PtrIrp) {
RetCode = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(Event);
return (RetCode);
}

IoSetCompletionRoutine(
PtrIrp,
ReadDiskCompletionRoutine,
Event,
TRUE,
TRUE,
TRUE
);

RetCode = IoCallDriver(PtrVCB->TargetDeviceObject,PtrIrp);

if (!NT_ERROR(RetCode)) {
KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
RetCode = IoStatusBlock.Status;
}

/* At this point, the return code is always status_buffer_too_small */

ExFreePool(Event);
return RetCode;

}
/****************************************************************************/


Sign up and get your 30GB webmail at www.30gigs.com now!

Specifying the IoStatusBlock just fills in the Irp field UserIosb. The I/O manager copies the status information to this location on completion. Since you are (correctly) short circuiting I/O completion with STATUS_MPR, the IoStatusBlock remains uninitialized. In your completion routine, copy Irp->IoStatus to *Irp->UserIosb, and you'll get the actual status.

  • Dan.

----- Original Message -----
From: xxxxx@30gigs.com
To: Windows File Systems Devs Interest List
Sent: Friday, March 10, 2006 6:42 AM
Subject: [ntfsd] Problem with using IoBuildAsynchronousFSDRequest

I am writing an FSD. I need a routine to read (contiguous sector aligned) data off the disk, so I rolled a function using IoBuildSynchronousFSDRequest. However, my routine needs to be able to work at APC_LEVEL, so I decided to replace it with IoBuildAsynchronousFSDRequest. Since the read disk function needs to be synchronous, I simply passed in a (pointer to) KEVENT type object (which was originally an argument to the IoBuildSynchrounous...) as the context to the completion routine, and signal it in the completion routine. However, this does not seem to work - while the first function using IoBuildSynchronousFSDRequest always completes successfully, the second one, after waiting, invariably returns STATUS_BUFFER_TOO_SMALL( -1073741789 = C0000023). I can't fathom why. I have attached the code below, any suggestions?
Sorry for the length of this query.

/********* TECHNIQUE 1: Use of IoBuildSynchronousFSDRequest ******/
NTSTATUS ReadDisk(IN P_VCB PtrVCB,IN ULONGLONG Offset, IN ULONG Size, IN PVOID Buffer, IO_STATUS_BLOCK IoStatusBlock)
{
PIRP PtrIrp = NULL;
NTSTATUS RetCode = STATUS_SUCCESS;
LARGE_INTEGER DiskOffset;
KEVENT Event;
DiskOffset.QuadPart = Offset;

KeInitializeEvent(&Event,NotificationEvent,FALSE);

ASSERT(PtrVCB->TargetDeviceObject);
PtrIrp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
PtrVCB->TargetDeviceObject,
Buffer,
Size,
&DiskOffset,
&Event,
&IoStatusBlock);
ASSERT(PtrIrp);
if(!PtrIrp) {
RetCode = STATUS_INSUFFICIENT_RESOURCES;
return (RetCode);

}
RetCode = IoCallDriver(PtrVCB->TargetDeviceObject,PtrIrp);

if (RetCode == STATUS_PENDING) {
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
RetCode = IoStatusBlock.Status;
}
return RetCode;
}

/*****************************************************************************/

/********* TECHNIQUE 2: Use of IoBuildAsynchronousFSDRequest ******/

NTSTATUS ReadDiskCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PVOID Context
)
{
PKEVENT Event = NULL;

Event = (PKEVENT) Context;

/* signal the waiting ReadDisk to continue */
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);

/* Free the Irp */
IoFreeIrp(Irp);

/* Return STATUS_MORE_PROCESSING_REQUIRED. This must always be returned for Asynchronous Irps */
return STATUS_MORE_PROCESSING_REQUIRED;

}

NTSTATUS ReadDisk(IN P_VCB PtrVCB,IN ULONGLONG Offset, IN ULONG Size, IN PVOID Buffer, IO_STATUS_BLOCK IoStatusBlock)
{
PIRP PtrIrp = NULL;
NTSTATUS RetCode = STATUS_SUCCESS;
LARGE_INTEGER DiskOffset;
KEVENT *Event = NULL;

DiskOffset.QuadPart = Offset;
Event = (KEVENT *) ExAllocatePoolWithTag(NonPagedPool,sizeof(KEVENT),'TEVE');
if(!Event) {
RetCode = STATUS_INSUFFICIENT_RESOURCES;
return (RetCode);
}

KeInitializeEvent(Event,NotificationEvent,FALSE);

ASSERT(PtrVCB->TargetDeviceObject);
PtrIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ,
PtrVCB->TargetDeviceObject,
Buffer,
Size,
&DiskOffset,
&IoStatusBlock);

if(!PtrIrp) {
RetCode = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(Event);
return (RetCode);
}

IoSetCompletionRoutine(
PtrIrp,
ReadDiskCompletionRoutine,
Event,
TRUE,
TRUE,
TRUE
);

RetCode = IoCallDriver(PtrVCB->TargetDeviceObject,PtrIrp);

if (!NT_ERROR(RetCode)) {
KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
RetCode = IoStatusBlock.Status;
}

/* At this point, the return code is always status_buffer_too_small */

ExFreePool(Event);
return RetCode;

}
/****************************************************************************/

Hi..! Get this Exclusive Offer From 30gigs.com. Free Ipod Nano! Click Here.
Don't have 30gigs email account yet? Sign up and get your 30GB Webmail account Now! --- Questions? First check the IFS FAQ at The NT Insider:Windows NT Virtual Memory (Part I) You are currently subscribed to ntfsd as: unknown lmsubst tag argument: '' To unsubscribe send a blank email to xxxxx@lists.osr.com