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!