Here is a snippet of my code:
NTSTATUS WriteComplete(In PDEVICE_OBJECT DeviceObject, In PIRP Irp,
In PVOID Context) {
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
PDEVICE_EXTENSION device_extension = DeviceObject->DeviceExtension;
PMDL r_mdl = (PMDL)Context;
PUCHAR r_ptr = MmGetSystemAddressForMdlSafe(r_mdl, NormalPagePriority);
if (NT_SUCCESS(Irp->IoStatus.Status) && Irp->IoStatus.Information != 0) {
//
// We’ve preread the data before the write occured.
// We’ve allowed the write to occur.
// Now we are in the final write completion handler
// with the buffer that was read.
//
}
// We do not need our intermediate read buffer anymore.
IoFreeMdl(r_mdl);
ExFreePool(r_ptr);
IoReleaseRemoveLock(&device_extension->remove_lock, NULL);
// Now it is OK to allow the IRP to do normal completion.
return STATUS_CONTINUE_COMPLETION;
UNREFERENCED_PARAMETER(Context);
}
NTSTATUS PreReadComplete(In PDEVICE_OBJECT DeviceObject, In PIRP Irp,
In PVOID Context) {
PMDL r_mdl = Irp->MdlAddress;
PMDL w_mdl = (PMDL)Context;
if (NT_SUCCESS(Irp->IoStatus.Status) && Irp->IoStatus.Information != 0) {
//
// We could do something interesting with the data read here,
// release the memory, and then proceed. However, in this example,
// and as an exercise, I’m passing the preread data all the way
// to the write completion handler.
//
}
// Set IRPs MDL back to the original write MDL.
Irp->MdlAddress = w_mdl;
PDEVICE_EXTENSION device_extension = DeviceObject->DeviceExtension;
// Pass the request along.
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, WriteComplete, r_mdl, TRUE, TRUE, TRUE);
// We must NOT mark the IRP pending here.
IoCallDriver(device_extension->target_device, Irp);
// Halt processing, and take control of the IRP again in the
// second completion handler.
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS Write(In PDEVICE_OBJECT DeviceObject, In PIRP Irp) {
PDEVICE_EXTENSION device_extension = DeviceObject->DeviceExtension;
NTSTATUS status = IoAcquireRemoveLock(&device_extension->remove_lock, NULL);
if (!NT_SUCCESS(status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
PIO_STACK_LOCATION c_stack = IoGetCurrentIrpStackLocation(Irp);
ULONG length = c_stack->Parameters.Write.Length;
if (length != 0) {
IoCopyCurrentIrpStackLocationToNext(Irp);
// Our filter device set DO_DIRECT_IO, so we can assume we will
// only receive MDLs in IRPs. This is just for tinkering anyway.
// Save the original MDL that contaisn the data being written.
PMDL w_mdl = Irp->MdlAddress;
// Allocate buffer for intermediate read request.
PVOID ptr = ExAllocatePool(NonPagedPool,
length < PAGE_SIZE ? PAGE_SIZE : length);
// Create an MDL for the intermediate read request.
PMDL r_mdl = IoAllocateMdl(ptr, length, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(r_mdl);
Irp->MdlAddress = r_mdl;
PIO_STACK_LOCATION n_stack = IoGetNextIrpStackLocation(Irp);
// Setup next stack location for read.
n_stack->MajorFunction = IRP_MJ_READ;
n_stack->Parameters.Read.ByteOffset = c_stack->Parameters.Write.ByteOffset;
n_stack->Parameters.Read.Key = c_stack->Parameters.Write.Key;
n_stack->Parameters.Read.Length = c_stack->Parameters.Write.Length;
IoSetCompletionRoutine(Irp, PreReadComplete, w_mdl, TRUE, TRUE, TRUE);
// Mark IRP pending BEFORE passing the request along.
IoMarkIrpPending(Irp);
IoCallDriver(device_extension->target_device, Irp);
// Because we have an intermediate completion handler that
// returns STATUS_MORE_PROCESSING_REQUIRED, we MUST return
// STATUS_PENDING.
return STATUS_PENDING;
}
else {
// Zero byte write; nothing to do.
IoReleaseRemoveLock(&device_extension->remove_lock, NULL);
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(device_extension->target_device, Irp);
}
}
On Sat, Jun 24, 2017 at 12:44 PM Jamey Kirby wrote:
> And I do NOT mark the irp pending on read complete.
>
> On Sat, Jun 24, 2017 at 12:43 PM Jamey Kirby
> wrote:
>
>> Oops, on the read completion, I do this:
>>
>> IoCallDriver();
>> return STATUS_MORE_PROCESSING_REQUIRED
>>
>>
>> On Sat, Jun 24, 2017 at 12:31 PM wrote:
>>
>>> I am tinkering with a volume filter. Here is what I am doing:
>>>
>>> On IRP_MJ_WRITE
>>> 1) allocate new mdl to match the write length parameter.
>>> 2) Save current irp mdl
>>> 3) Replace mdl in irp with new mdl
>>> 4) IoCopyCurrentIrpStackLocationToNext()
>>> 5) IoGetNextIrpStackLocation()
>>> 6) Change irp next sl from a write to a read.
>>> 7) IoSetCompletionRotuine(Irp, read_complete, saved_mdl, TRUE, TRUE,
>>> TRUE);
>>> 8) return IoCallDriver()
>>>
>>> On IRP_MJ_READ completion
>>> 1) Do something interesting with the data read and then delete the new
>>> mdl.
>>> 2) Change the mdl in the irp to the one passed in the context.
>>> 3) IoSkipCurrentIrpStackLocation()
>>> 4) return IoCallDriver()
>>>
>>> The code seems to be working OK. Is this safe?
>>>
>>>
>>> —
>>> NTDEV is sponsored by OSR
>>>
>>> Visit the list online at: <
>>> http://www.osronline.com/showlists.cfm?list=ntdev>
>>>
>>> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
>>> software drivers!
>>> Details at http:
>>>
>>> To unsubscribe, visit the List Server section of OSR Online at <
>>> http://www.osronline.com/page.cfm?name=ListServer>
>>>
>></http:>