IoCompleteRequest深入学习之二

本文深入解析了IRP(I/O请求包)完成例程的实现细节,包括如何检查IRP的状态、处理完成例程及释放资源等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 接上篇还原为c的代码如下:

VOID FASTCALL IopfCompleteRequest(
                                    IN PIRP Irp,
                                    IN CCHAR PriorityBoost
                                )
{
    UCHAR uControl;
    PIRP masterIrp;
    NTSTATUS status;
    PIO_STACK_LOCATION stackPointer;
    PIO_STACK_LOCATION bottomSp;
    PDEVICE_OBJECT deviceObject;
    PMDL mdl;
    PETHREAD thread;
    PFILE_OBJECT fileObject;
    KIRQL irql;
    PVOID saveAuxiliaryPointer = NULL;
    NTSTATUS    errorStatus;

    /*检查请求包的栈单元域是否处理完 */

    if (Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1) ||
        Irp->Type != 6)
    {
        KeBugCheckEx( 0x44,(ULONG_PTR)Irp, 0x0D63, 0, 0 );
    }

   /*     如果栈单元没有耗尽,设置栈单元指针指向下一个栈单元并且如果当前栈单元中有完成例程,
           则进行调用。清空栈单元。逐个检查每个栈单元,直到栈单元耗尽。
           如果一个特殊的驱动中,当其需要执行大量的处理,或者需要在其他进程的上下文中执行,
           调用完成例程完成IRP时,返回 STATUS_MORE_PROCESSING_REQUIRED 即:0x0C0000016。
           如果当前完成例程返回STATUS_MORE_PROCESSING_REQUIRED,则停止处理这个请求包。
   */
    for (stackPointer = IoGetCurrentIrpStackLocation( Irp ),
         Irp->CurrentLocation++,
         Irp->Tail.Overlay.CurrentStackLocation++;
         Irp->CurrentLocation <= (CCHAR) (Irp->StackCount + 1);
         stackPointer++,
         Irp->CurrentLocation++,
         Irp->Tail.Overlay.CurrentStackLocation++)
   {

        Irp->PendingReturned = stackPointer->Control & 1;


        if ( (NT_SUCCESS( Irp->IoStatus.Status ) &&
             stackPointer->Control & 0x40) ||
             (!NT_SUCCESS( Irp->IoStatus.Status ) &&
             stackPointer->Control & 0x80) ||
             (Irp->Cancel &&
             stackPointer->Control & 0x20)
           )
        {


             stackPointer->MinorFunction = 0;
             stackPointer->Flags = 0;
             stackPointer->Control = 0;
             stackPointer->Parameters.Others.Argument1 = 0;
             stackPointer->Parameters.Others.Argument2 = 0;
             stackPointer->Parameters.Others.Argument3 = 0;
             stackPointer->FileObject = 0;           

            if (Irp->CurrentLocation == (CCHAR) (Irp->StackCount + 1))
            {
                deviceObject = NULL;
            }
            else
            {
                deviceObject = IoGetCurrentIrpStackLocation( Irp )->DeviceObject;
            }

            status = stackPointer->CompletionRoutine( deviceObject,
                                                      Irp,
                                                      stackPointer->Context );

            if (status == 0x0C0000016)
            {
                 return;
            }

        }
        else
        {
            if (Irp->PendingReturned && Irp->CurrentLocation <= Irp->StackCount)
            {
                IoMarkIrpPending( Irp );
            }
            stackPointer->MinorFunction = 0;
            stackPointer->Flags = 0;
            stackPointer->Control = 0;
            stackPointer->Parameters.Others.Argument1 = 0;
            stackPointer->Parameters.Others.Argument2 = 0;
            stackPointer->Parameters.Others.Argument3 = 0;
            stackPointer->FileObject = 0;           
        }
    }

   /*    检查当前的IRP是否是一个关联的IRP。 如果是,主IRP计数递减。如果主IRP计数为0,
          则按照正常IRP的完成步骤完成主IRP。如果计数仍然不是0,那么当前的IRP将被简单的释放.   */
   if (Irp->Flags & 8)
   {
        ULONG count;

        masterIrp = Irp->AssociatedIrp.MasterIrp;

        count = IopInterlockedDecrementUlong( 0x0A,
                                            &masterIrp->AssociatedIrp.IrpCount );

        IopFreeIrpAndMdls( Irp );
        if (count == 1)
        {
            IoCompleteRequest( masterIrp, PriorityBoost ); //递归
        }
        return;
   }

   /* Check to see if we have a name junction*/
   if ((Irp->IoStatus.Status == 0x104 ) &&
        (Irp->IoStatus.Information > 1))
   {

        /* For name junctions, we save the pointer to the auxiliary
           buffer and use it below.*/
        if (Irp->IoStatus.Information == 0x0A0000003)
        {

            saveAuxiliaryPointer = (PVOID) Irp->Tail.Overlay.AuxiliaryBuffer;
            Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
        }
        else
        {

            Irp->IoStatus.Status = 0x0C0000279h ;
        }
   }
  

   /*检查IRP中的辅助缓冲区指针,如果不为NULL,则释放*/
   if (Irp->Tail.Overlay.AuxiliaryBuffer)
   {
        ExFreePoolWithTag (Irp->Tail.Overlay.AuxiliaryBuffer,0 );
        Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
    }

   /*如果这是一个内存分页的I/O或者是一个关闭操作,那么保存I/O状态块,并且把事件设置为信号态,
       并取消事件的引用。如果是内存分页的I/O,还需要释放IRP.
   */
   if (Irp->Flags & 0x402)
   {
        if (Irp->Flags & 0x440)
        {
            ULONG flags;

            flags = Irp->Flags & 0x42;
            *Irp->UserIosb = Irp->IoStatus;

            (VOID) KeSetEvent( Irp->UserEvent, PriorityBoost, 0 );
            if (flags)
            {
                if (IopIsReserveIrp(Irp))
                {
                    IopFreeReserveIrp(PriorityBoost);
                }
                else
                {
                    IoFreeIrp( Irp );
                }
            }
        }
        else
        {
         
            KeInitializeApc( &Irp->Tail.Apc,
                             Irp->Tail.Overlay.Thread,
                             Irp->ApcEnvironment,
                             IopCompletePageWrite,
                             (PKRUNDOWN_ROUTINE) NULL,
                             (PKNORMAL_ROUTINE) NULL,
                             KernelMode,
                             (PVOID) PriorityBoost );
           
            (VOID) KeInsertQueueApc( &Irp->Tail.Apc,
                                     (PVOID) NULL,
                                     (PVOID) NULL,
                                     PriorityBoost );
        }
        return;
    }
  
   /*页面解锁,如果需要,调用MmUnlockPages来释放MDL*/
   if (Irp->MdlAddress != NULL)
   {

        mdl = Irp->MdlAddress;
        while (mdl != NULL)
        {
            MmUnlockPages( mdl );
            mdl = mdl->Next;
        }
   }

   /*检查请求完成是否可以延迟完成,如果可以,当前的完成例程可以简单退出,直到原始的请求完成IRP,
      通过初始化和派发APC到调用线程,可以避免很多的中断和排队处理。*/

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

        if ((Irp->IoStatus.Status == 0x104 ) &&
            (Irp->IoStatus.Information == 0x0A0000003))
        {

            Irp->Tail.Overlay.AuxiliaryBuffer = saveAuxiliaryPointer;
        }

        return;
    }
//
    fileObject = Irp->Tail.Overlay.OriginalFileObject;

    if (!Irp->Cancel)
   {

        KeInitializeApc( &Irp->Tail.Apc,
                         &Irp->Tail.Overlay.Thread,
                         Irp->ApcEnvironment,
                         IopCompleteRequest,
                         IopAbortRequest,
                         (PKNORMAL_ROUTINE) NULL,
                         KernelMode,
                         (PVOID) NULL );

        (VOID) KeInsertQueueApc( &Irp->Tail.Apc,
                                 fileObject,
                                 (PVOID) saveAuxiliaryPointer,
                                 PriorityBoost );
    }
   else
   {
        /*IRP被取消时,派发APC到目标线程。*/

        irql = KeRaiseIrqlToDpcLevel() ;

        thread = Irp->Tail.Overlay.Thread;

        if (thread)
        {

            KeInitializeApc( &Irp->Tail.Apc,
                             &thread,
                             Irp->ApcEnvironment,
                             IopCompleteRequest,
                             IopAbortRequest,
                             (PKNORMAL_ROUTINE) NULL,
                             KernelMode,
                             (PVOID) NULL );

            (VOID) KeInsertQueueApc( &Irp->Tail.Apc,
                                     fileObject,
                                     (PVOID) saveAuxiliaryPointer,
                                     PriorityBoost );

            KfLowerIrql (irql );

        }
        else
        {

            KfLowerIrql (irql );

            IopDropIrp( Irp, fileObject );

        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值