IRP 处理浅析

来源:互联网 发布:长沙理工大学教务网络 编辑:程序博客网 时间:2024/05/21 17:10

1. IRP 的总体结构(IoAllocateIrp)

#define IoSizeOfIrp(_StackSize) \  ((USHORT) (sizeof(IRP) + ((_StackSize) * (sizeof(IO_STACK_LOCATION)))))PIRPIoAllocateIrp(IN CCHAR StackSize,              IN BOOLEAN ChargeQuota){    PIRP Irp = NULL;    USHORT Size = IoSizeOfIrp(StackSize);    Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);    IoInitializeIrp(Irp, Size, StackSize);    return Irp;}

2. IRP 如何使用 - 1(IoBuildDeviceIoControlRequest

         (1)分配 IRP

         (2)设置下一层 IO_STACK_LOCARION (IRP_MJ_Xxx / Parameters)

         (3)设置 IRP 内容 (读写缓冲区)

         (4)把 IRP 与线程相关联 (即把 IRP 设置成同步 IRP)


3. IRP 如何使用 - 2(转发并忘记

         (1)IoSkipCurrentIrpStackLocation

         (2)return IoCallDriver ( pLowerDevice , pIrp );


NTSTATUSIofCallDriver(IN PDEVICE_OBJECT DeviceObject,              IN PIRP Irp){    DriverObject = DeviceObject->DriverObject;    Irp->CurrentLocation--;    StackPtr = IoGetNextIrpStackLocation(Irp);    Irp->Tail.Overlay.CurrentStackLocation = StackPtr;    /* Get the Device Object */    StackPtr->DeviceObject = DeviceObject;    /* Call it */    return DriverObject->MajorFunction[StackPtr->MajorFunction](DeviceObject, Irp);}


4. IRP 如何使用 - 3(前进并等待

         (1)IoSetCompletionRoutine

         (2)IoCallDriver

         (3)KeWaitForSingleObject


#define IoSetCompletionRoutine(_Irp, \                               _CompletionRoutine, \                               _Context, \                               _InvokeOnSuccess, \                               _InvokeOnError, \                               _InvokeOnCancel) \{ \  PIO_STACK_LOCATION _IrpSp; \  _IrpSp = IoGetNextIrpStackLocation(_Irp); \  _IrpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)(_CompletionRoutine); \  _IrpSp->Context = (_Context); \  _IrpSp->Control = 0; \  if (_InvokeOnSuccess) _IrpSp->Control = SL_INVOKE_ON_SUCCESS; \  if (_InvokeOnError) _IrpSp->Control |= SL_INVOKE_ON_ERROR; \  if (_InvokeOnCancel) _IrpSp->Control |= SL_INVOKE_ON_CANCEL; \}

5. IRP 的完成与返回(IoCompleteRequest

         (1)设置 pIrp->IoStatus

         (2)IoCompleteRequest

         (3)return STATUS_Xxx


VOIDIofCompleteRequest(IN PIRP Irp,                   IN CCHAR PriorityBoost){    /*     * Start the loop with the current stack and point the IRP to the next stack     * and then keep incrementing the stack as we loop through. The IRP should     * always point to the next stack location w.r.t the one currently being     * analyzed, so completion routine code will see the appropriate value.     * Because of this, we must loop until the current stack location is +1 of     * the stack count, because when StackPtr is at the end, CurrentLocation is +1.     */    for (StackPtr = IoGetCurrentIrpStackLocation(Irp),         Irp->CurrentLocation++,         Irp->Tail.Overlay.CurrentStackLocation++;         Irp->CurrentLocation <= (Irp->StackCount + 1);          StackPtr++,         Irp->CurrentLocation++,         Irp->Tail.Overlay.CurrentStackLocation++)    {        /* 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 = UlongToPtr(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);        }    }    ......}


6. 完成函数的返回值 ( STATUS_CONTINUE_COMPLETION / STATUS_MORE_PROCESSING_REQUIRED )

         (1)当完成函数的返回值为 STATUS_CONTINUE_COMPLETION 时,IoCompleteRequest 继续向上遍历 IO_STACK_LOCATION

         (2)当完成函数的返回值为 STATUS_MORE_PROCESSING_REQUIRED 时,IoCompleteRequest 不再继续向上遍历 IO_STACK_LOCATION 


7. 同步IRP 与 异步 IRP


Synchronous (Threaded) IRPAsynchronous (Non-Threaded) IRPCreated by using IoBuildSynchronousFsdRequest orIoBuildDeviceIoControlRequest.Created by using IoBuildAsynchronousFsdRequest orIoAllocateIrp. This is meant for driver to driver communication.Thread must wait for the IRP to complete.Thread does not have to wait for the IRP to complete.Associated with the thread that created it, hence, the name threaded IRPs. Therefore, if the thread exits, the I/O manager cancels the IRP.Not associated with the thread that created it.Cannot be created in an arbitrary thread context.Can be created in an arbitrary thread context because the thread does not wait for the IRP to complete.The I/O manager does the post completions to free the buffer that is associated with the IRP.The I/O manager cannot do the cleanup. The driver must provide a completion routine and free the buffers that are associated with the IRP.Must be sent at IRQL level equal to PASSIVE_LEVEL.Can be sent at IRQL less than or equal to DISPATCH_LEVEL if the Dispatch routine of the target driver can handle the request at DISPATCH_LEVEL.


参加文献:

ReactOS 0.3.15 Src

Different ways of handling IRPs - cheat sheet







0 0
原创粉丝点击