Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting...
Please check out the Community Guidelines in the Announcements and Administration Category.

Yoyoing an Irp

Jamey_KirbyJamey_Kirby Member - All Emails Posts: 433
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?

Comments

  • Jamey_KirbyJamey_Kirby Member - All Emails Posts: 433
    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
    >
    > To unsubscribe, visit the List Server section of OSR Online at <
    > http://www.osronline.com/page.cfm?name=ListServer>;
    >
  • Jamey_KirbyJamey_Kirby Member - All Emails Posts: 433
    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
    >>
    >> To unsubscribe, visit the List Server section of OSR Online at <
    >> http://www.osronline.com/page.cfm?name=ListServer>;
    >>
    >
  • Jamey_KirbyJamey_Kirby Member - All Emails Posts: 433
    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
    >>>
    >>> To unsubscribe, visit the List Server section of OSR Online at <
    >>> http://www.osronline.com/page.cfm?name=ListServer>;
    >>>
    >>
  • Slava_ImameevSlava_Imameev Member Posts: 480
    <QUOTE>
    NTSTATUS PreReadComplete
    {
    ....
    IoCallDriver(device_extension->target_device, Irp);
    }
    </QUOTE>

    If an Irp is being completed at DISPATCH_LEVEL the underlying filters and the volume manager driver will have a hard time to process this reused IRP. The only strategy for them is to mark IRP pending, post it to a worker thread and return immediately. I am not sure they are designed to process write requests with scheduler being disabled.
  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 7,345
    I guess I don't understand the question.

    Is WHAT safe, specifically?

    Peter
    OSR
    @OSRDrivers

    Peter Viscarola
    OSR
    @OSRDrivers

  • Jamey_KirbyJamey_Kirby Member - All Emails Posts: 433
    This is the first time I've done this; yoyo'ed an IRP. It works, and I like
    it, but something feels slightly uncomfortable about it. I can't put my
    finger on it. Also, I probably should change the IRP flags to indicate read
    operation vs. write operation with IRP_READ_OPERATION and
    IRP_WRITE_OPERATION. Although it seems redundant.

    -- Jamey

    On Sun, Jun 25, 2017 at 9:16 AM wrote:

    > I guess I don't understand the question.
    >
    > Is WHAT safe, specifically?
    >
    > Peter
    > OSR
    > @OSRDrivers
    >
    >
    > ---
    > 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
    >
    > To unsubscribe, visit the List Server section of OSR Online at <
    > http://www.osronline.com/page.cfm?name=ListServer>;
    >
  • OSR_Community_UserOSR_Community_User Member Posts: 110,217
    Why do you allocate a new MDL if you do not have a new buffer ?

    The swapbuffer sample does this but with a new buffer allocated from non-paged pool.

    H. G.
  • Jamey_KirbyJamey_Kirby Member - All Emails Posts: 433
    First I allocate new buffer from nonpaged pool (see the Write() functions),
    then I create an MDL for it, and replace the MDL in the IRP. I guess I
    could just swap out the buffer in the current MDL. I'd still have to mark
    the MDL as using NPP. How would I unmark the MDL when I was ready to swap
    back to the original buffer? It seems to me that creating a new MDL is the
    easiest method for my NPP buffer. I don't know the performance impedance of
    creating a new MDL each time. I suspect it is nominal compared to the fact
    that I am issuing a read before every write.)

    If I were not creating a new buffer, my driver would be whacky for sure; on
    every write, I's be reading what was already on the disk and then writing
    that back out. Not to mention I'd be overwriting a callers buffer on direct
    IO. We could call it "Active Write Protection" :)


    On Sun, Jun 25, 2017 at 11:32 AM wrote:

    > Why do you allocate a new MDL if you do not have a new buffer ?
    >
    >
    >
    > The swapbuffer sample does this but with a new buffer allocated from
    > non-paged pool.
    >
    >
    >
    > H. G.
    >
    >
    >
    > ---
    > 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
    >
    > To unsubscribe, visit the List Server section of OSR Online at <
    > http://www.osronline.com/page.cfm?name=ListServer>;
    >
  • Alex_GrigAlex_Grig Member Posts: 3,238
    >If an Irp is being completed at DISPATCH_LEVEL the underlying filters and the
    volume manager driver will have a hard time to process this reused IRP

    A storage IRP is completed at DISPATCH_LEVEL most of the time.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
Developing Minifilters 29 July 2019 OSR Seminar Space
Writing WDF Drivers 23 Sept 2019 OSR Seminar Space
Kernel Debugging 21 Oct 2019 OSR Seminar Space
Internals & Software Drivers 18 Nov 2019 Dulles, VA