반응형

IoCompleteRequest in ReactOS

 

 

VOID NTAPI IoCompleteRequest(IN PIRP Irp, IN CCHAR PriorityBoost)

{

    /* Call the fastcall */

    IofCompleteRequest(Irp, PriorityBoost);

}

 

 

VOID FASTCALL IofCompleteRequest(IN PIRP Irp, IN CCHAR PriorityBoost)

{

    PIO_STACK_LOCATION StackPtr, LastStackPtr;

    PDEVICE_OBJECT DeviceObject;

    PFILE_OBJECT FileObject;

    PETHREAD Thread;

    NTSTATUS Status;

    PMDL Mdl, NextMdl;

    ULONG MasterCount;

    PIRP MasterIrp;

    ULONG Flags;

    NTSTATUS ErrorCode = STATUS_SUCCESS;

   

           IOTRACE(IO_IRP_DEBUG, "%s - Completing IRP %p\n", __FUNCTION__, Irp);

 

    /* Make sure this IRP isn't getting completed twice or is invalid */

    if ((Irp->CurrentLocation) > (Irp->StackCount + 1))

    {

        /* Bugcheck */

        KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0);

    }

 

    /* Some sanity checks */

    ASSERT(Irp->Type == IO_TYPE_IRP);

    ASSERT(!Irp->CancelRoutine);

    ASSERT(Irp->IoStatus.Status != STATUS_PENDING);

    ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF);

 

    /* Get the last stack */

    LastStackPtr = (PIO_STACK_LOCATION)(Irp + 1);

    if (LastStackPtr->Control & SL_ERROR_RETURNED)

    {

        /* Get the error code */

        ErrorCode = (NTSTATUS)LastStackPtr->Parameters.Others.Argument4;

    }

 

    /* Get the Current Stack and skip it */

    StackPtr = IoGetCurrentIrpStackLocation(Irp);

    IoSkipCurrentIrpStackLocation(Irp);

 

    /* Loop the Stacks and complete the IRPs */

    do

    {

        /* Set Pending Returned */

        Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;

 

        /* Check if we failed */

        if (!NT_SUCCESS(Irp->IoStatus.Status))

        {

            /* Check if it was changed by a completion routine */

            if (Irp->IoStatus.Status != ErrorCode)

            {

                /* Update the error for the current stack */

                ErrorCode = Irp->IoStatus.Status;

                StackPtr->Control |= SL_ERROR_RETURNED;

                LastStackPtr->Parameters.Others.Argument4 = (PVOID)ErrorCode;

                LastStackPtr->Control |= SL_ERROR_RETURNED;

            }

        }

 

        /* Check if there is a Completion Routine to Call */

        if ((NT_SUCCESS(Irp->IoStatus.Status) && (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||

            (!NT_SUCCESS(Irp->IoStatus.Status) && (StackPtr->Control & SL_INVOKE_ON_ERROR)) ||

            (Irp->Cancel && (StackPtr->Control & SL_INVOKE_ON_CANCEL)))

        {

            /* Clear the stack location */

            IopClearStackLocation(StackPtr);

 

            /* Check for highest-level device completion routines */

            if (Irp->CurrentLocation == (Irp->StackCount + 1))

            {

                /* Clear the DO, since the current stack location is invalid */

                DeviceObject = NULL;

            }

            else

            {

                /* Otherwise, return the real one */

                DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;

            }

 

            /* Call the completion routine */

            Status = StackPtr->CompletionRoutine(DeviceObject, Irp, StackPtr->Context);

 

            /* Don't touch the Packet in this case, since it might be gone! */

            if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;

        }

        else

        {

            /* Otherwise, check if this is a completed IRP */

            if ((Irp->CurrentLocation <= Irp->StackCount) && (Irp->PendingReturned))

            {

                /* Mark it as pending */

                IoMarkIrpPending(Irp);

            }

 

            /* Clear the stack location */

            IopClearStackLocation(StackPtr);

        }

 

        /* Move to next stack location and pointer */

        IoSkipCurrentIrpStackLocation(Irp);

        StackPtr++;

    } while (Irp->CurrentLocation <= (Irp->StackCount + 1));

 

    /* Check if the IRP is an associated IRP */

    if (Irp->Flags & IRP_ASSOCIATED_IRP)

    {

        /* Get the master IRP and count */

        MasterIrp = Irp->AssociatedIrp.MasterIrp;

        MasterCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);

 

        /* Free the MDLs */

        for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)

        {

            /* Go to the next one */

            NextMdl = Mdl->Next;

            IoFreeMdl(Mdl);

        }

 

        /* Free the IRP itself */

        IoFreeIrp(Irp);

 

        /* Complete the Master IRP */

        if (!MasterCount) IofCompleteRequest(MasterIrp, PriorityBoost);

        return;

    }

 

    /* We don't support this yet */

    ASSERT(Irp->IoStatus.Status != STATUS_REPARSE);

 

    /* Check if we have an auxiliary buffer */

    if (Irp->Tail.Overlay.AuxiliaryBuffer)

    {

        /* Free it */

        ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer);

        Irp->Tail.Overlay.AuxiliaryBuffer = NULL;

    }

 

    /* Check if this is a Paging I/O or Close Operation */

    if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION))

    {

        /* Handle a Close Operation or Sync Paging I/O */

        if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))

        {

            /* Set the I/O Status and Signal the Event */

            Flags = Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO);

            *Irp->UserIosb = Irp->IoStatus;

            KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);

 

            /* Free the IRP for a Paging I/O Only, Close is handled by us */

            if (Flags) IoFreeIrp(Irp);

        }

        else

        {

#if 0

            /* Page 166 */

            KeInitializeApc(&Irp->Tail.Apc

                            &Irp->Tail.Overlay.Thread->Tcb,

                            Irp->ApcEnvironment,

                            IopCompletePageWrite,

                            NULL,

                            NULL,

                            KernelMode,

                            NULL);

            KeInsertQueueApc(&Irp->Tail.Apc,

                             NULL,

                             NULL,

                             PriorityBoost);

#else

            /* Not implemented yet. */

            DPRINT1("Not supported!\n");

            while (TRUE);

#endif

        }

 

        /* Get out of here */

        return;

    }

 

    /* Unlock MDL Pages, page 167. */

    Mdl = Irp->MdlAddress;

    while (Mdl)

    {

                     MmUnlockPages(Mdl);

        Mdl = Mdl->Next;

    }

 

    /* Check if we should exit because of a Deferred I/O (page 168) */

    if ((Irp->Flags & IRP_DEFER_IO_COMPLETION) && !(Irp->PendingReturned))

    {

        /*

         * Return without queuing the completion APC, since the caller will

         * take care of doing its own optimized completion at PASSIVE_LEVEL.

         */

        return;

    }

 

    /* Get the thread and file object */

    Thread = Irp->Tail.Overlay.Thread;

    FileObject = Irp->Tail.Overlay.OriginalFileObject;

 

    /* Make sure the IRP isn't canceled */

    if (!Irp->Cancel)

    {

        /* Initialize the APC */

        KeInitializeApc(&Irp->Tail.Apc,

                        &Thread->Tcb,

                        Irp->ApcEnvironment,

                        IopCompleteRequest,

                        NULL,

                        NULL,

                        KernelMode,

                        NULL);

 

        /* Queue it */

        KeInsertQueueApc(&Irp->Tail.Apc,

                         FileObject,

                         NULL, /* This is used for REPARSE stuff */

                         PriorityBoost);

    }

    else

    {

        /* The IRP just got canceled... does a thread still own it? */

        Thread = Irp->Tail.Overlay.Thread;

        if (Thread)

        {

            /* Yes! There is still hope! Initialize the APC */

            KeInitializeApc(&Irp->Tail.Apc,

                            &Thread->Tcb,

                            Irp->ApcEnvironment,

                            IopCompleteRequest,

                            NULL,

                            NULL,

                            KernelMode,

                            NULL);

 

            /* Queue it */

            KeInsertQueueApc(&Irp->Tail.Apc,

                             FileObject,

                             NULL, /* This is used for REPARSE stuff */

                             PriorityBoost);

        }

        else

        {

            /* Nothing left for us to do, kill it */

            ASSERT(Irp->Cancel);

            IopCleanupIrp(Irp, FileObject);

        }

    }

}

 

반응형

+ Recent posts