[WDF] EvtIoRead with Buffered IO vs Direct IO

So I’m fooling around, learning WDF and I have 2 non-PnP drivers.

I send a read request from one driver to the other like this:

 status = WdfMemoryCreatePreallocated(WDF_NO_OBJECT_ATTRIBUTES,   
 gDrvData.ReadTestBuffer,   
 sizeof(gDrvData.ReadTestBuffer),   
 &gDrvData.ReadTestMemory);  
 if (!NT_SUCCESS(status))  
 {  
 DbgPrint("[ERROR] WdfMemoryCreatePreallocated failed: 0x%x\n", status);  
 goto _cleanup_and_exit;  
 }  
  
WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&openParams, &gMiscData.TargetName, GENERIC_ALL);  
  
status = WdfIoTargetCreate(gDrvData.Device, WDF_NO_OBJECT_ATTRIBUTES, &ioTarget);  
 if (!NT_SUCCESS(status))  
 {  
 DbgPrint("[ERROR] WdfIoTargetCreate failed: 0x%x\n", status);  
 goto _cleanup_and_exit;  
 }  
 status = WdfIoTargetOpen(ioTarget, &openParams);  
 if (!NT_SUCCESS(status))  
 {  
 DbgPrint("[ERROR] WdfIoTargetOpen failed: 0x%x\n", status);  
 goto _cleanup_and_exit;  
 }  
  
WDF_OBJECT_ATTRIBUTES_INIT(&objAttr);  
 objAttr.ParentObject = ioTarget;  
  
status = WdfRequestCreate(&objAttr, ioTarget, &request);  
 if (!NT_SUCCESS(status))  
 {  
 DbgPrint("[ERROR] WdfRequestCreate failed: 0x%x\n", status);  
 goto _cleanup_and_exit;  
 }  
  
status = WdfIoTargetFormatRequestForRead(ioTarget, request, gDrvData.ReadTestMemory, NULL, NULL);  
 if (!NT_SUCCESS(status))  
 {  
 DbgPrint("[ERROR] WdfIoTargetFormatRequestForRead failed: 0x%x\n", status);  
 goto _cleanup_and_exit;  
 }  
  
WdfRequestSetCompletionRoutine(request, CompletionRoutineRead, NULL);  
  
bSend = WdfRequestSend(request, ioTarget, WDF_NO_SEND_OPTIONS);  
 DbgPrint("[ERROR] WdfRequestSend: %s\n", bSend ? "TRUE" : "FALSE");  
  
WdfIoTargetClose(ioTarget);  

My completion routine simply checks and prints what is in that buffer.
And in the driver that receives the request I handle it like this:

 status = WdfRequestRetrieveOutputBuffer(Request, 0, &pBuf, &size);  
 if (!NT_SUCCESS(status))  
 {  
 DbgPrint("[ERROR] WdfRequestRetrieveOutputBuffer failed: 0x%x\n", status);  
 goto _cleanup_and_exit;  
 }  
  
RtlCopyMemory(pBuf, localTestBuf, sizeof(localTestBuf));  
  
_cleanup_and_exit:  
 WdfRequestComplete(Request, status);  

Now, if in my initialization routine I set the IO method to buffered, the content I receive after the Request is completed is not the one I wrote. If the method is Direct, I have the correct content in the buffer.

What am I missing here?

* I know I should use KdPrint, but I’m used to writing DbgPrint every time I want to log something.

You’re not calling WdfRequestCompleteWithInformation and supplying the number of data bytes returned from the driver in the user’s data buffer.

That’ll fix you up.

VERY common error for new Windows driver developers, so don’t feel bad…

Peter
OSR
@OSRDrivers

Thanks :slight_smile:

So the reason this is working with Direct IO is because there I use directly the buffer supplied when the request is made and with Buffered IO I actually receive another buffer and at the end the framework will do a copy from the buffer I received to the original one?

> So the reason this is working with Direct IO is because there I use directly the buffer supplied when

the request is made and with Buffered IO I actually receive another buffer and at the end the
framework will do a copy from the buffer I received to the original one?

Yes.

More so, this is NT kernel/WDM feature, not even a KMDF feature.

If you return the data to the caller (like the read path does), you must fill Irp->IoStatus.Information to nonzero, either in WDM or in KMDF (using KMDF abstraction for it).


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com