挂起当前IRP

挂起当前IRP

如果需要将IRP异步完成, 一般不会在处理函数中调用IoCompleteRequest函数, 因为调用IoCompleteRequest函数就意味着,该IRP请求处理完成了, 事实上很多时候是需要多次处理, 或者有其他需求的, 这边先谈谈将当前IRP挂起.

挂起意味着,是异步操作, 那么需要等待以后某个时机再处理, 当然这个时机问题的话, 以后会了解到, 目前需要解决的是挂起当前IRP的方法.

下面这个驱动的功能就是这样, 将所有的IRP都挂起, 在最后Win32这边调用CloseHandle的时候再统一处理, 完成那些IRP请求. 一种异步完成IRP的例子. 除了挂起还要取消什么的. 下一篇说.

主要说说这一篇的挂起操作. 挂起其实也很简单, 就是不调用IoCompleteRequest, 改为调用IoMarkIrpPending. 当然这些IRP需要自己用某种手段存放起来, 不然的话回头取就不知道怎么取出来了, 这边用的是系统提供的双向链表了. 调用IoMarkIrpPending以后返回STASTUS_PENDING那么, Win32调用函数这边就会返回ERROR_IO_PENDING, 当然这样并不代表有错误的, 只是IRP还没有完成而已..

这几天兴致不是很高啊, 上代码吧. 这边是用户层的.

001/*
002    Windows内核下挂起当前IRP, 在IRP_MJ_CLEANUP中统一完成 3环代码
003    编译方法参见makefile. TAB = 8
004*/
005#include <stdio.h>
006#include <windows.h>
007 
008#pragma comment( linker, "/Entry:Jmain" )
009 
010#define SYS_LINK_NAME   "\\\\.\\SysLinkPendingIrp"
011//===========================================================================
012//线程等待函数
013//===========================================================================
014DWORD WINAPI ThreadProc( LPVOID lpParameter ) {
015    HANDLE hEvent;
016 
017    hEvent = *( HANDLE* )lpParameter;
018    printf( "线程开始进入等待状态!\n" );
019    WaitForSingleObject( hEvent, INFINITE );
020    ExitThread( 0 );
021}
022 
023//===========================================================================
024//用户层的启动函数
025//===========================================================================
026int __stdcall Jmain( int argc, char* argv[] ) {
027    HANDLE  hFile = 0;
028    BOOL    bRet;
029    DWORD   dwByteWrite;
030    HANDLE  hThread[2] = {0};
031    DWORD   dwThreadId[2];
032    BYTE    byBuf[10];
033    OVERLAPPED StOverLapped1 = {0};
034    OVERLAPPED StOverLapped2 = {0};
035 
036    __try {
037        //异步打开设备. 下面操作的函数都是异步的
038        hFile = CreateFile( SYS_LINK_NAME, GENERIC_READ | GENERIC_WRITE,
039                            0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0 );
040 
041        if ( hFile == INVALID_HANDLE_VALUE ) {
042            printf( "打开设备失败!\n" );
043            return -1;
044        }
045 
046        //创建两个事件用于异步读取文件
047        StOverLapped1.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
048        StOverLapped2.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
049 
050        //创建两个线程等待内核设置事件, 不然看不到效果
051        hThread[0] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped1.hEvent, 0, &dwThreadId[0]  );
052 
053        if ( hThread[0] == NULL ) {
054            printf( "创建线程1失败!\n" );
055            return -1;
056        }
057 
058        hThread[1] = CreateThread( NULL, 0, &ThreadProc, &StOverLapped2.hEvent, 0, &dwThreadId[1]  );
059        if ( hThread[1] == NULL ) {
060            printf( "创建线程2失败!\n" );
061        }
062 
063        Sleep( 1000 );
064//---------------------------------------------------------------------------
065        //向设备发送了两次写入请求, 都会被挂起.
066//---------------------------------------------------------------------------
067        RtlFillMemory( byBuf, sizeof( byBuf ), 'a' );
068        bRet =  WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped1 );
069 
070        if ( !bRet && GetLastError() != ERROR_IO_PENDING ) {
071            printf( "写入设备失败\n" );
072            return -1;
073        }
074 
075        RtlFillMemory( byBuf, sizeof( byBuf ), 'b' );
076        bRet =  WriteFile( hFile, byBuf, sizeof( byBuf ), &dwByteWrite, &StOverLapped2 );
077 
078        if ( !bRet && GetLastError() != ERROR_IO_PENDING ) {
079            printf( "写入设备失败\n" );
080            return -1;
081        }
082 
083        if ( hFile ) {
084            CloseHandle( hFile );
085        }
086 
087        //等待多个对象返回(必须同时返回)
088        WaitForMultipleObjects( 2, hThread, TRUE, INFINITE );
089        printf( "两个对象都已经返回!\n" );
090//---------------------------------------------------------------------------
091    } __finally {
092        if ( hThread[0] ) {
093            CloseHandle( hThread[0] );
094        }
095 
096        if ( hThread[1] ) {
097            CloseHandle( hThread[1] );
098        }
099 
100        if ( StOverLapped1.hEvent ) {
101            CloseHandle( StOverLapped1.hEvent );
102        }
103 
104        if ( StOverLapped2.hEvent ) {
105            CloseHandle( StOverLapped2.hEvent );
106        }
107 
108        if ( hFile ) {
109            CloseHandle( hFile );
110        }
111        system( "pause" );
112    }
113 
114    return 0;
115}

这边是内核态的代码:

001/*
002    Windows内核下挂起当前IRP, 在IRP_MJ_CLEANUP中统一完成 0环代码
003    编译方法参见makefile. TAB = 8
004*/
005#include <ntddk.h>
006 
007#define DEVICE_NAME L"\\Device\\DevPendingIrp"
008#define SYS_LINK_NAME   L"\\??\\SysLinkPendingIrp"
009 
010//---------------------------------------------------------------------------
011typedef struct tagDevice_Ext {
012    PDEVICE_OBJECT  pDeviceObj;
013    PLIST_ENTRY pIrpListHead;   //链表头结点, 用于存放IRP请求
014    UNICODE_STRING  USzDeviceName;
015    UNICODE_STRING  USzSysLinkName;
016} DEVICE_EXT, *PDEVICE_EXT;
017 
018typedef struct Irp_Entry {
019    PIRP pIRP;
020    LIST_ENTRY ListEntry;
021} IRP_ENTRY, *PIRP_ENTRY;
022//===========================================================================
023//驱动卸载例程
024//===========================================================================
025#pragma  code_seg( "PAGE" )
026VOID    DriverUnLoad( PDRIVER_OBJECT pDriverObj ) {
027    PDEVICE_EXT pDeviceExt = NULL;
028    PDEVICE_OBJECT pNextDevice = NULL;
029 
030    PAGED_CODE();
031    pNextDevice = pDriverObj->DeviceObject;
032 
033    while ( pNextDevice != NULL ) {
034        pDeviceExt = pNextDevice->DeviceExtension;
035 
036        IoDeleteDevice( pDeviceExt->pDeviceObj );
037        IoDeleteSymbolicLink( &pDeviceExt->USzSysLinkName );
038        KdPrint( ( "删除%wZ设备成功!\n", &pDeviceExt->USzDeviceName ) );
039 
040        pNextDevice = pNextDevice->NextDevice;
041    }
042}
043//===========================================================================
044//所有不关心的IRP处理例程
045//===========================================================================
046NTSTATUS DispatchRoutine( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
047 
048    PAGED_CODE();
049 
050    pIrp->IoStatus.Information = 0;
051    pIrp->IoStatus.Status = STATUS_SUCCESS;
052    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
053    return STATUS_SUCCESS;
054}
055//===========================================================================
056//IRP_MJ_WRITE的处理, 将所有的IRP都返回为pending状态
057//===========================================================================
058NTSTATUS DispatchWrite( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
059    PDEVICE_EXT pDeviceExt = NULL;
060    PIRP_ENTRY pIrpEntry = NULL;
061 
062    PAGED_CODE();
063 
064    pDeviceExt = pDeviceObj->DeviceExtension;
065    ASSERT( pDeviceExt != NULL );
066 
067    pIrpEntry = ( PIRP_ENTRY )ExAllocatePool( PagedPool, sizeof( IRP_ENTRY ) );
068    ASSERT ( pIrpEntry != NULL );
069    pIrpEntry->pIRP = pIrp;
070 
071    //插入队列
072    InsertHeadList( pDeviceExt->pIrpListHead, &pIrpEntry->ListEntry );
073 
074    //将IRP设置为挂起
075    IoMarkIrpPending( pIrp );
076    KdPrint( ( "在IRP_MJ_WRITE请求中将IRP挂起!\n" ) );
077    //返回pending状态
078    return STATUS_PENDING;
079}
080//===========================================================================
081//将未决的写入请求完成
082//===========================================================================
083NTSTATUS Write_CompleteRequest( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
084    ULONG i;
085    ULONG ulWriteLength;
086    ULONG ulWriteOffset;
087    PIO_STACK_LOCATION WriteStack = NULL;
088 
089    PAGED_CODE();
090    WriteStack = IoGetCurrentIrpStackLocation( pIrp );
091 
092    //欲写入的长度, 偏移
093    ulWriteLength = WriteStack->Parameters.Write.Length;
094    ulWriteOffset = ( ULONG )WriteStack->Parameters.Write.ByteOffset.QuadPart;
095 
096    for( i = 0; i < ulWriteLength; i++ ) {
097        KdPrint( ( "%c\t", *( ( ( UCHAR* )pIrp->AssociatedIrp.SystemBuffer ) + i ) ) );
098    }
099 
100    KdPrint( ( "\n" ) );
101 
102    //简单的完成IRP请求
103    pIrp->IoStatus.Status = STATUS_SUCCESS;
104    pIrp->IoStatus.Information = ulWriteLength;
105    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
106    KdPrint( ( "写入请求处理完毕!\n" ) );
107    return STATUS_SUCCESS;
108}
109//===========================================================================
110//IRP_MJ_CLEANUP IRP的处理, 将IRP_MJ_WRITE未决的IRP全部处理下
111//===========================================================================
112NTSTATUS DispatchCleanUp( PDEVICE_OBJECT pDeviceObj, PIRP pIrp ) {
113    NTSTATUS    Status;
114    PDEVICE_EXT pDeviceExt = NULL;
115    PIRP_ENTRY  pIrpEntry = NULL;
116    PLIST_ENTRY pListEntry = NULL;
117 
118    PAGED_CODE();
119    pDeviceExt = ( PDEVICE_EXT ) pDeviceObj->DeviceExtension;
120    Status = STATUS_UNSUCCESSFUL;
121 
122    for( ; !IsListEmpty( pDeviceExt->pIrpListHead ); pIrpEntry = NULL ) {
123 
124        pListEntry = RemoveTailList( pDeviceExt->pIrpListHead );
125 
126        //获取IRP的数据指针
127        pIrpEntry = CONTAINING_RECORD( pListEntry, IRP_ENTRY, ListEntry );
128 
129        if ( !pIrpEntry ) {
130            KdPrint( ( "获取结点数据失败!\n" ) );
131            Status = STATUS_UNSUCCESSFUL;
132        } else {
133            //完成写入请求
134            Status = Write_CompleteRequest( pDeviceObj, pIrpEntry->pIRP );
135 
136            if ( !NT_SUCCESS( Status ) ) {
137                KdPrint( ( "完成写入请求时失败!\n" ) );
138            }
139 
140            ExFreePool( pIrpEntry );
141 
142            KdPrint( ( "未决请求处理完成!\n" ) );
143        }
144    }
145 
146    //处理IRP_MJ_CLEANUP自身的IRP请求
147    pIrp->IoStatus.Status = Status;
148    pIrp->IoStatus.Information = 0;
149    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
150    return Status;
151}
152//===========================================================================
153//驱动程序的入口函数
154//===========================================================================
155#pragma code_seg( "INIT" )
156NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pUSzRegPath ) {
157    ULONG i;
158    NTSTATUS Status;
159    PDEVICE_OBJECT pDevice = NULL;
160    PDEVICE_EXT pDeviceExt = NULL;
161    UNICODE_STRING USzDeviceName = RTL_CONSTANT_STRING( DEVICE_NAME );
162    UNICODE_STRING UszSysLink = RTL_CONSTANT_STRING( SYS_LINK_NAME );
163 
164    Status = IoCreateDevice( pDriverObj, sizeof( DEVICE_EXT ), &USzDeviceName,
165                             FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevice );
166 
167    if ( !NT_SUCCESS( Status ) ) {
168        KdPrint( ( "创建设备失败!\n" ) );
169        return Status;
170    }
171 
172    Status = IoCreateSymbolicLink( &UszSysLink, &USzDeviceName );
173 
174    if ( !NT_SUCCESS( Status ) ) {
175        IoDeleteDevice( pDevice );
176        KdPrint( ( "创建符号链接失败!\n" ) );
177        return Status;
178    }
179 
180    //带缓冲区的IO方式
181    pDevice->Flags |= DO_BUFFERED_IO;
182    pDeviceExt = pDevice->DeviceExtension;
183    pDeviceExt->pDeviceObj = pDevice;
184    pDeviceExt->USzDeviceName = USzDeviceName;
185    pDeviceExt->USzSysLinkName = UszSysLink;
186 
187    //初始化链表头结点
188    pDeviceExt->pIrpListHead = ( PLIST_ENTRY )ExAllocatePool( PagedPool, sizeof( LIST_ENTRY ) );
189    InitializeListHead( pDeviceExt->pIrpListHead );
190 
191    //设置分发函数, 驱动卸载函数
192    for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
193        pDriverObj->MajorFunction[i] = &DispatchRoutine;
194    }
195 
196    pDriverObj->DriverUnload = &DriverUnLoad;
197    pDriverObj->MajorFunction[IRP_MJ_WRITE] = &DispatchWrite;
198    pDriverObj->MajorFunction[IRP_MJ_CLEANUP] = &DispatchCleanUp;
199 
200    return Status;
201}

 

<think>嗯,用户现在问的是关于“他的irp结构是什么”。首先,我需要确认用户提到的“他”指的是什么。根据之前的对话历史,用户之前询问了关于nsiproxy的内容,所以很可能这里的“他的irp结构”指的是nsiproxy相关的IRP结构。 接下来,我需要回想IRP在Windows内核中的基本概念。IRP是I/O请求包,用于驱动程序之间的通信。每个I/O操作都会由I/O管理器创建IRP,并发送给相应的驱动程序处理。这可能涉及到多个驱动程序,每个驱动处理一部分IRP,然后传递给下一个驱动。 用户可能想知道nsiproxy.sys这个驱动程序如何处理IRP,或者它的IRP处理结构是怎样的。需要解释IRP的结构,以及nsiproxy在其中的作用。例如,nsiproxy可能作为网络存储接口的代理,处理特定的IRP类型,如设备控制请求(IOCTL)或者读写请求。 还要考虑用户的技术水平。之前的对话中用户询问了系统级组件,可能具备一定的技术背景,但可能需要较为详细的解释。需要分步骤介绍IRP的结构,并结合nsiproxy的实际应用场景,比如在协调网络协议或资源同步时如何使用IRP。 同时,需要注意用户是否有更深层的需求。比如,用户可能在遇到驱动或系统崩溃的问题,想通过了解IRP结构来诊断问题。因此,除了结构解释外,可能需要加入一些诊断或常见问题的解决方法,比如如何分析IRP相关的错误。 另外,确保回答符合之前的格式要求,使用中文,结构清晰,分点说明。需要检查之前的回答是否涉及IRP,如果没有,需要详细展开,但保持连贯性。可能需要包括IRP的定义、主要字段、处理流程,以及nsiproxy如何处理这些IRP,比如传递、完成或修改请求。 还要注意用户可能混淆了某些术语,比如将IRP与其他内核结构混淆,需要明确IRP的作用和组成部分。最后,可能需要给出实际例子,帮助用户理解,比如在文件共享或网络通信中IRP如何被使用,以及nsiproxy在其中扮演的角色。</think>以下是关于**IRP(I/O Request Packet)结构**的逐步解释,结合其在Windows内核(如`nsiproxy.sys`等驱动)中的作用: --- ### 1. **IRP 的定义** IRP(**I/O Request Packet**)是Windows内核中用于**管理I/O操作的核心数据结构**。当用户模式程序(如应用程序)或内核组件发起I/O请求(如读写文件、网络通信)时,I/O管理器会创建一个IRP,并将其传递给目标驱动程序处理。 --- ### 2. **IRP 的核心结构** IRP在代码中通常表现为`_IRP`结构体(C语言定义),包含以下关键字段: | 字段名 | 描述 | |-------------------------|----------------------------------------------------------------------| | **MdlAddress** | 指向内存描述符列表(MDL),描述用户缓冲区在内核模式中的物理映射。 | | **Flags** | 标志位,表示IRP类型(如同步/异步请求、直接I/O等)。 | | **AssociatedIrp** | 关联的IRP指针,用于复杂I/O操作的分层处理。 | | **IoStatus** | 包含操作状态(`Status`字段)和传输字节数(`Information`字段)。 | | **RequestorMode** | 指示请求来源(用户模式或内核模式)。 | | **Tail.Overlay** | 存储设备栈信息,如当前处理的驱动栈位置(`CurrentStackLocation`)。 | | **MajorFunction** | 主功能码(如`IRP_MJ_READ`、`IRP_MJ_WRITE`、`IRP_MJ_DEVICE_CONTROL`)。| --- ### 3. **IRP 的生命周期** #### 阶段1:创建 - **触发场景**:应用程序调用API(如`ReadFile`)或内核组件发起I/O请求。 - **I/O管理器**创建IRP,初始化`MajorFunction`(指定操作类型)和`Parameters`(存储参数)。 #### 阶段2:传递 - IRP通过**设备栈(Device Stack)**逐层传递,每个驱动通过`DriverObject->MajorFunction`处理对应操作。 **示例**:网络请求可能依次经过协议驱动(如TCP/IP)、过滤驱动(如防火墙)、物理网卡驱动。 #### 阶段3:完成 - 底层驱动处理完成后,调用`IoCompleteRequest`标记IRP为完成状态。 - I/O管理器将结果返回给发起者(如应用程序)。 --- ### 4. **nsiproxy.sys 与 IRP 的交互** 作为网络存储代理驱动,`nsiproxy.sys`主要处理以下IRP类型: 1. **`IRP_MJ_DEVICE_CONTROL`** 处理来自用户模式的IOCTL(设备控制)请求,例如配置网络命名空间或同步共享资源。 2. **`IRP_MJ_CREATE`/`IRP_MJ_CLOSE`** 管理网络资源(如SMB共享路径)的打开与关闭。 3. **`IRP_MJ_READ`/`IRP_MJ_WRITE`** 中转网络数据读写请求(较少直接处理,通常转发给下层驱动)。 --- ### 5. **IRP 的调试与常见问题** #### 典型问题 - **IRP未完成(Pending)** 驱动未调用`IoCompleteRequest`,导致请求挂起,最终引发系统无响应或超时错误。 - **内存泄漏** 未正确释放IRP关联的缓冲区(如忘记释放`MdlAddress`映射的内存)。 #### 调试工具 - **WinDbg** 使用`!irp <IRP地址>`命令查看IRP的详细状态和堆栈。 **示例**: ```bash 0: kd> !irp 0xffffa508a4d3d010 Irp is active with 3 stacks 3 is current (= 0xffffa508a4d3d1b8) No Mdl: No System Buffer: Thread 00000000: Irp stack trace. cmd flg cl Device File Completion-Context [ 0, 0] 0 0 00000000 00000000 00000000-00000000 Args: 00000000 00000000 00000000 00000000 ``` --- ### 6. **总结** IRP是Windows内核I/O操作的核心载体,其结构复杂但高度标准化。驱动(如`nsiproxy.sys`)通过处理特定类型的IRP实现功能,开发或调试时需严格遵循IRP生命周期管理规则,避免系统稳定性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值