IRP(I/O Request Package)详解
篇一:
简介:
IRP(I/O Request Package)
在windows
内核中,有一种系统组件——IRP
,即输入输出请求包。
当上层应用程序需要访问底层输入输出设备时,发出I/O
请求,系统会把这些请求转化为IRP
数据,不同的IRP
会启动I/O
设备驱动中对应的派遣函数。
IRP
类型
由于IRP
是响应上层应用程序的。可想而知,IRP
类型是与上层对底层设备的访问类型相对应。
文件相关的I/O
函数如:CreateFile/ReadFile/WriteFile/CloseHandle
等,操作系统就会将其转为
IRP_MJ_CREATE/IRP_MJ_READ/IRP_MJ_WRITE/IRP_MJ_CLOSE
等IRP
类型,这些IRP
再被传送到驱动程序的派遣函数中。
IRP
列表如下:
名称 | 描述 | 调用者 |
---|---|---|
IRP_MJ_CREATE | 请求一个句柄 |
CreateFile
|
IRP_MJ_CLEANUP | 在关闭句柄时取消悬挂的IRP |
CloseHandle
|
IRP_MJ_CLOSE | 关闭句柄 |
CloseHandle
|
IRP_MJ_READ | 从设备得到数据 |
ReadFile
|
IRP_MJ_WRITE | 传送数据到设备 |
WriteFile
|
IRP_MJ_DEVICE_CONTROL | 控制操作(利用IOCTL宏) |
DeviceIoControl
|
RP_MJ_INTERNAL_DEVICE_CONTROL | 控制操作(只能被内核调用) |
N/A
|
IRP_MJ_QUERY_INFORMATION | 得到文件的长度 |
GetFileSize
|
IRP_MJ_SET_INFORMATION | 设置文件的长度 |
SetFileSize
|
IRP_MJ_FLUSH_BUFFERS | 写输出缓冲区或者丢弃输入缓冲区 |
FlushFileBuffers
|
FlushConsoleInputBuffer
|
||
PurgeComm
|
||
IRP_MJ_SHUTDOWN | 系统关闭 |
InitiateSystemShutdown
|
IRP
对应的派遣函数处理过程
多数的IRP
都来自于Win32 API
函数,如CreateFile
,ReadFile
,WriteFile
函数等等。
一种简单的IRP
派遣函数的实现就是:将该IRP
中的状态置为成功(pIRP->IoStatus =STATUS_SUCCESS
),然后结束该IRP
请求(调用I噢CompleteRequest
函数),并返回成功状态。
NTSTATUS status = STATUS_SUCCESS;
// 完成IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutin\n")); return status;
VOID IoCompleteRequest(IN PIRP Irp,IN CCHAR PriorityBoost);
下面以ReadFile
为例,详细介绍。
ReadFile
调用ntdll中的N他ReadFile
。其中ReadFile
函数是Win32 API
,而NtReadFile
函数是Native API
。ntdll
中的N他ReadFile
进入内核模式,并调用系统服务中的N他ReadFile
函数。- 系统服务函数N他
ReadFile
创建IRP_MJ_WRITE
类型的IRP
,然后将这个IRP
函数发送到对应驱动程序的派遣函数中。 - 在对应的派遣函数中一般会通过
IoCompleteRequest
函数将IRP
请求结束。
篇2:
第5章 I/O Request Packet
5.1 数据结构
在处理 I/O
请求上,有两个重要的数据结构:IRP(I/O request packet)
和 IO_STACK_LOCATION
5.1.1 IRP
的结构
下面是在 windbg
里得到的 IRP
结构:
nt!_IRP+0x000 Type : Int2B+0x002 Size : Uint2B+0x004 MdlAddress : Ptr32 _MDL+0x008 Flags : Uint4B+0x00c AssociatedIrp : <unnamed-tag>+0x010 ThreadListEntry : _LIST_ENTRY+0x018 IoStatus : _IO_STATUS_BLOCK+0x020 RequestorMode : Char+0x021 PendingReturned : UChar+0x022 StackCount : Char+0x023 CurrentLocation : Char+0x024 Cancel : UChar+0x025 CancelIrql : UChar+0x026 ApcEnvironment : Char+0x027 AllocationFlags : UChar+0x028 UserIosb : Ptr32 _IO_STATUS_BLOCK+0x02c UserEvent : Ptr32 _KEVENT+0x030 Overlay : <unnamed-tag>+0x038 CancelRoutine : Ptr32 void +0x03c UserBuffer : Ptr32 Void+0x040 Tail : <unnamed-tag>
MdlAddress
用来描述 user-mode buffer
的 MDL
(memory descriptor list
),这个域仅用于“direct I/O
”。
假如最上层的 device object
的 flags
标志设置为 DO_DIRECT_IO
时:
(1) I/O
建立 IRP_MJ_READ
和 IRP_MJ_WRITE
时使用 MDL
。
(2) I/O
建立 IRP_MJ_DEVICE_CONTROL
时假如 control
代码为 METHOD_IN_DIRECT
或 METHOD_OUT_DIRECT
,使用 MDL
。
MDL
描述 user-mode virtual buffer
也包含对应的 physical address
,driver
使用它能尽快地访问 user-mode buffer
。
AssociatedIrq
是一个 union
成员,它的结构如下:
union {struct _IRP *MasterIrp; // 此 IRP 是 associate IRP,它指向 master IRPLONG IrpCount; // 此 IRP 是 master IRP,它指示 associate IRP 的个数PVOID SystemBuffer; // 此 IRP 是 master IRP,它指向 system buffer
} AssociatedIrp; // 用于和 user-mode buffer 进行数据交换。
AssociatedIrq.SystemBuffer
指向 kernel-mode nonpaged
的 data buffer
区域,它使用在下面情形:
(1) 在 IRP_MJ_READ
和 IRP_MJ_WRITE
操作里,假如最上层的 device object
的 flags
提供了 DO_BUFFERED_IO
(2) 在 IRP_MJ_DEVICE_CONTROL 操作里,假如 I/O control code 指示需要 buffer。调用 WriteFile() 或者 DeviceIoControl() 用作输入 data
I/O manager 复制 user-mode data buffer 到 kernel-mode data buffer 里。
(3) 在读操作里,I/O manager 复制 kernel-mode data buffer 到 user-mode data buffer 里。
IoStatus 是一个结构体,包含了两个域:Status
与 Information
。IoStatus.Status 接收 NTSTATUS
码,而 IoStatus.Information 是 ULONG 类型,
接收一个确切的值依赖于 IRP 的类型和完成的状态。一个通常的用法是:Information
域保存传送数据的 bytes
数(例如在 IRP_MJ_READ 操作上)。
它的结构类似如下:
typedef struct _IO_STATUS_BLOCK
{union {ULONG Status;PVOID Pointer;};ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
RequestorMode
是 UserMode
或者 KernelMode
这个值之一。
CancelRoutine
是 driver 中 IRP cancel routine 的地址,需要使用 IoSetCancelRoutine()
设置,避免直接对它进行设置。
UserBuffer
是保存 user-mode
的 data buffer
,与 kernel-mode data buffer
进行数据交换。
最后是 Tail
成员,它是一个 union
变量,这个 Tail
比较复杂,它的结构如下:
union
{struct{union{ KDEVICE_QUEUE_ENTRY DeviceQueueEntry;struct{PVOID DriverContext[4];};};PETHREAD thread;PCHAR AuxiliaryBuffer;struct{LIST_ENTRY ListEntry;union{struct _IO_STACK_LOCATION *CurrentStackLocation;ULONG PacketType;};};PFILE_OBJECT OriginalFileObject;} Overlay;KAPC Apc;PVOID CompletionKey;} Tail;
Tail union
包括三个部分:Overlay
,Apc
以及 CompletionKey
。
5.1.2 I/O
stack
当 kernel-mode
程序建立一个 IRP
时,它同时也建立相应的 IO_STACK_LOCATION
结构的数组,每个元素被称为 stack location
。
一个 stack location
包含着 IRP
的 type
和 parameter
信息,也包含着 completion routine
地址,它的结构如下:
nt!_IO_STACK_LOCATION+0x000 MajorFunction : UChar+0x001 MinorFunction : UChar+0x002 Flags : UChar+0x003 Control : UChar+0x004 Parameters : <unnamed-tag>+0x014 DeviceObject : Ptr32 _DEVICE_OBJECT+0x018 FileObject : Ptr32 _FILE_OBJECT+0x01c CompletionRoutine : Ptr32 long +0x020 Context : Ptr32 Void
其中,Parameters
成员定义为一个复杂的 union
结构,如下:
union
{//// NtCreateFIle 参数//struct {PIO_SECURITY_CONTEXT SecurityContext;ULONG Options;USHORT POINTER_ALIGNMENT FileAttributes;USHORT ShareAccess;ULONG POINTER_ALIGNMENT EaLength;} Create;//// NtCreateNamedPipeFile 参数//struct{PIO_SECURITY_CONTEXT SecurityContext;ULONG Options;USHORT POINTER_ALIGNMENT Reserved;USHORT SharedAccess;PNAMED_PIPE_CREATE_PARAMETERS Parameters;} CreatePipe;//// NtCreateMailsotFIle 参数//struct{PIO_SECURITY_CONTEXT SecurityContext;ULONG Options;USHORT POINTER_ALIGNMENT Reserved;USHORT SharedAccess;PMAILSLOT_CREATE_PARAMETERS Parameters;} CreateMailslot;//// NtReadFile 参数//struct{ULONG Length;ULONG PINTER_ALIGNMENT Key;LARGE_INTEGER ByteOffset;} Read;//// NtWriteFile 参数//struct{ULONG Length;ULONG POINTER_ALIGNMENT Key;LARGE_INTEGER ByteOffset;} Write;//// NtQueryDirectoryFile 参数//struct{ULONG Length;PSTRING FileName;FILE_INFORMATION_CLASS FileInformationClass;ULONG POINTER_ALIGNMENT FileIndex;} QueryDirectory;//// NtNotifyChangeDirectoryFile 参数//struct{ULONG Length;ULONG POINTER_ALIGNMENT CompletionFilter;} NotifyDirectory;//// NtQueryInformationFile 参数//struct{ULONG Length;FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;} QueryFile;//// NtSetInformationFile 参数//struct{ULONG Length;FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;PFILE_OBJECT FileObject;union{struct{BOOLEAN ReplaceIfExists;BOOLEAN AdvanceOnly;};ULONG ClusterCount;HANDLE DeleteHandle;};} SetFile;//// NtQueryEaFile 参数//struct{ULONG Length;PVOID EaList;ULONG EaListLength;ULONG POINTER_ALIGNMENT EaIndex;} QueryEa;//// NtSetEaFIle 参数//struct{ULONG Length;} SetEa;//// NtQueryVolumeInformationFile 参数//struct{ULONG Length;FS_INORTMATION_CLASS POINTER_ALIGNMENT FsInformationClass;} QueryVoume;// // NtSetVolumeInformationFile 参数//struct {ULONG Length;FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;} setValue;//// NtFsControlFile 参数//struct{ULONG OutputBufferLength;ULONG POINTER_ALIGNMENT InputBufferLength;ULONG POINTER_ALIGNMENT FsControlCode;PVOID Type3InputBuffer;} FileSystemControl;//// NtLockFile/NtUnlockFile 参数//struct{PLARGE_INTEGER Length;ULONG POINTER_ALIGNMENT Key;LARGE_INTEGER ByteOffset;} LockControl;//// NtDeviceIoControlFile 参数//struct{ULONG OutputBufferLength;ULONG POINTER_ALIGNMENT InputBufferLength;ULONG POINTER_ALIGNMENT IoControlCode;PVOID Type3InputBuffer;} DeviceIoControl;//// NtQuerySecurityObject 参数//struct{SECURITY_INFORMATION SecurityInformation;ULONG POINTER_ALIGNMENT Length;} QuerySecurity;//// NtSetScurityObject 参数//struct{SECURITY_INFORMATION SecurityInformation;PSECURITY_DESCRIPTOR SecurityDescriptor;} SetSecurity;//// MountVoluem 参数//struct{PVPB Vpb;PDEVICE_OBJECT DeviceObject;} MountVolume;//// VerifyVolume 参数//struct{PVPB Vpb;PDEVICE_OBJECT DeviceObject;} VerityVolume;//// Scsi 内部 device control//struct{struct _SCSI_REQUEST_BLOCK *Srb;} Scsi;//// NtQueryQuotaInformationFile 参数//struct{ULONG Length;PSID StartSid;PFILE_GET_QUOTA_INFORMATION SidList;ULONG SidListLength;} QueryQuota;//// NtSetQuotaInformationFile 参数//struct{ULONG Length;} SetQuota;//// IRP_MN_QUERY_DEVICE_RELATIONS 参数//struct{DEVICE_RELATION_TYPE Type;} QueryDevceRelations;//// IRP_MN_QUERY_INTERFACE 参数//struct{CONST GUID *InterfaceType;USHORT Size;USHORT Version;PINTERFACE Interface;PVOID InterfacespecificData;} QueryInterface;//// IRP_MN_QUERY_CAPABILITIES 参数//struct{PDEVICE_CAPABILITIES Capabilities;} DeviceCapabilities;//// IRP_MN_FILTER_RESOURCE_REQUIREMENTS 参数//struct{PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;} FilterResourceRequirements;//// IRP_MN_READ_CONFIG 和 IRP_MN_WRITE_CONFIG 参数//struct{ULONG WhichSpace;PVOID Buffer;ULONG Offset;ULONG POINTER_ALIGNMENT Length;} ReadWriteConfig;//// IRP_MN_SET_LOCK 参数//struct{BOOLEAN Lock;} SetLock;//// IRP_MN_QUERY_ID 参数//struct{BUS_QUERY_ID_TYPE IdType; } QueryId;//// IRP_MN_QUERY_DEVICE_TEXT 参数//struct{DEVICE_TEXT_TYPE DeviceTextType;LCID POINTER_ALIGNMENT LocaleId;} QueryDeviceText;//// IRP_MN_DEVICE_USAGE_NOTIFICATION 参数//struct{BOOLEAN InPath;BOOLEAN Reserved[3];DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;} UsageNotification;//// IRP_MN_WAIT_WAKE 参数//struct{SYSTEM_POWER_STATE PowerState;} WaitWake;//// IRP_MN_POWER_SEQUENCE 参数//struct{PPOWER_SEQUENCE PowerSequence;} PowerSquence;//// IRP_MN_SET_POWER 和 IRP_MN_QUERY_POWER 参数//struct{ULONG SystemCotext;POWER_STATE_TYPE POINTER_ALIGNMENT Type; POWER_STATE POINTER_ALIGNMENT State;POWER_ACTION POINTER_ALIGNMENT ShutdownType;} Power;//// StartDevice 参数//struct{PCM_RESOURCE_LIST AllocatedResources;PCM_RESOURCE_LIST AllocatedResourcesTranslated;} StartDevice;//// WMI Irps 参数//struct{ULONG_PTR ProviderId;PVOID DataPath;ULONG BufferSize;PVOID Buffer;} WMI;//// 其它 device 提供的参数//struct{PVOID Argument1PVOID Argument2;PVOID Argument3;PVOID Argument4;} Others;} Parameters;
Parameters
为每个类型的 request
提供参数,例如:Create(IRP_MJ_CREATE
请求),Read(IRP_MJ_READ
请求),StartDevice(IRP_MJ_PNP
的子类 IRP_MN_START_DEVICE
)
MajorFunction
和 MinorFunction
分别的 IRP
的主功能号和子功能号。DeviceObject
是 stack entry
相应的 device object
,IoCallDriver()
将填写此域。
FileObject
指向 kernel file object
。driver
经常使用这个 FileObject
指向关联的 IRP
在一个 request
队列里。
CompletionRoutine
是提供一个 I/O completion routine
,不要直接设置这个域,而是使用 IoSetCompletionRoutine()
来设置。
Context
是任意的值,传递给 completion routine
作为参数。不要直接设置这个域,而是使用 IoSetCompletionRoutine()
来设置。
5.2 IRP
处理的标准模式
下面几个阶段:
I/O manager ---> Dispatch routine ---> StartIo routine ---> ISR ---> DPC routine ---> I/O manager
5.2.1 建立一个 IRP
IRP
的生存期从调用 I/O manager function
建立 IRP
开始,你可以使用下面 4 个 function
来建立一个新的 IRP
:
(1) IoBuildAsynchronousFsdRequest()
: 建立一个 IRP 不希望等待。这个函数只适合用于某类的 IRP
(2) IoBuildSynchronousFsdRequest()
: 建立一个 IRP 需要等待完成。
(3) IoBuildDeviceIoControlRequest()
: 建立一个同步的 IRP_MJ_DEVICE_CONTROL
或者 IRP_MJ_INTERNAL_DEVICE_CONTROL
(4) IoAllcateIrp()
: 建立一个 asynchronous
的 IRP
>>> 建立 synchronous IRP
使用 IoBuildSynchronousFsdRequest()
或 IoBuildDeviceIoControlRequest()
来建立同步的 IRP
,同步 IRP
是属于创建者线程。
由它有一个物主,由此有下面的一系列结果:
(1) 假如物主线程终止,I/O manager
自动取消属于该线程的同步 IRP
的 pending
(2) 由于创建线程拥有这个同步 IRP
的缘故,你不能在任意线程 context
里创建同步 IRP
,当物主线程终止后不能请求 I/O manager
取消 IRP
。
(3) 调用 IoCompleteRequest()
,I/O manager
自动清同步 IRP
,并且置你必须提供的 event
置 signaled
状态。
(4) 在 I/O manager
置 event object signaled
状态后,event object
仍存在时你必须小心地处理 event object
。
必须在 PASSIVE_LEVEL
里调用这两个函数,特别是不能在 APC_LEVEL
级别上。因为:在获得 fast mutex
后进入到 APC_LEVEL
,然后 I/O manager
不能提交 special APC routine
去处理所有 complete
处理。
PIRP Irp = IoBuildSycnhronousFsdRequest(...);
ExAcqurireFastMutex(...);
NTSTATUS status = IoCallDriver(...);
if (status == STATUS_PENDING)
{KeWaitForSingleObject(...); // 错误:不要这样做
}
ExReleaseFastMutex(...);
在上面的代码里,使用 KeWaitForSingleObject()
等待会进入死锁:当完成执行 IoCompleteRequest()
,这个 APC routine
运行将设置 event
,
因为已经在 APC_LEVEL
级别上,APC routine
不能运行去设置 event signled
。
假如你需要发送一个 synchronous IRP
到其它 driver
,考虑下面的选择:
(1) 使用定期的 kernel mutex
来代替 fast mutex
,kernel mutex
将返回到 PASSIVE_LEVEL
级别上,并不会抑制 special APC
执行。
(2) 使用 KeEnterCriticalRegion()
来抑制所有除了 special APC
外,然后使用 ExAcquireFastMutexUnsafe()
来获得 mutex
。
(3) 使用 asynchronous IRP
(代替 synchronous IRP
),完成后 signaled event
。
这两个函数所建立的 IRP
为下表所示:
support function IRP 类型
------------------------------------------------------------------------------------
IoBuildSynchronousFsdRequest() IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN
IRP_MJ_PNP
IRP_MJ_POWER(仅用于 IRP_MN_POWER_SEQUENCE)
-------------------------------------------------------------------------------------
IoBuildDeviceControlRequest() IRP_MJ_DEVICE_CONTROLIRP_MJ_INTERNAL_DEVICE_CONTROL>>> 建立异步 IRP
IoBuildAsynchronousFsdRequest() 和 IoAllocateIrp() 这两上函数建立异步的 IRP,这些可以建立 IRP 如下表所示:support function IRP 类型
--------------------------------------------------------------------------------------
IoBuildAsynchronousFsdRequest() IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN
IRP_MJ_PNP
IRP_MJ_POWER(仅用于 IRP_MN_POWER_SEQUENCE)
---------------------------------------------------------------------------------------
IoAllocateIrp() 任何(但必须初始化 Marjor function 表)
异步 IRP
不属于创建者线程,当 IRP
完成后,I/O manager
不调用 APC
以及不清理 IRP
。考虑下面的问题:
(1) 当线程终止后,I/O manager
不会取消任何异步 IRP
的 pending
(2) 可以在任意线程 context
里创建
(3) 由于 IRP
完成后 I/O manager
不清理 IRP
,你必须提供一个complete routine
去释放 buffer
以及调用 IoFreeIrp()
释放 IRP
所使用的内存。
(4) 当长时期没发生操作时,你可能需要提供一个 cancel routine
。
(5) 由于不需要等待异步 IRP
的完成,你可以创建 IRP
在 IRQL <= DISPATCH_LEVEL
级别上,当获得 fast mutex
发送异步 IRP
是可以的。
5.2.2 dispatch routine
当建立一个 IRP
后,可以使用 IoGetNextIrpStackLocation()
来获得 first stack location
,然后需要对 stack location
进行初始化。
如果是使用 IoAllcateIrp()
建立的需要填写相关的 MajorFunction
表。
PEDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION stack = IoGetNextIrpStackLoction(Irp);
stack->MajorFunction = IRP_MJ_Xxx;
// ... stack 初始化代码
NTSTATUS status = IoCallDriver(DeviceObject, Irp);IoGetNextIrpStackLocation() 是一个宏用来获得当前的 stack location,它的定义如下:
#define IoGetNextIrpStackLocation(Irp) ((Irp)->Tail.Overlay.CurrentStackLocation - 1)
>>> What IoCallDriver
Does
IoCallDriver()
看起来像下面:
NTSTATUS IoCallDriver(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{IoSetNextIrpStackLocation(Irp);PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);Stack->DeviceObject = DeviceObject;ULONG fcn = Stack->MajorFunction;PDRVIER_OBJECT Driver = DeviceObject->DriverObject;return (*Driver->MajorFunction[fcn]))(DeviceObject, Irp);
}
IoCallDriver()
简单地调用 stack
指针对应的 driver
的 dispatch routine
。
>>> location device objects
除了使用 IoAttachDeviceToDeviceStack()
外,可以使用另外的两个方法:IoGetDeviceObjectPointer()
和 IoGetAttachedDeviceReference()
NTSTATUS IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,IN ACCESS_MASK DesiredAccess,OUT PFILE_OBJECT *FileObject,OUT PDEVICE_OBJECT *DeviceObject);
假如你知道 device object
的名字,那么你可以使用这个函数 IoGetDeviceObjectPointer()
得到 device object
,像下面的用法:
PUNICODE_STRING devname;
ASSESS_MASK access;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
NTSTATUS status;ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
status = IoGetDeviceObjectPointer(devname, access, &FileObject, &DeviceObject);
这个函数返回两个指针:一个指向 FILE_OBJECT
, 一个指向 DEVICE_OBJECT
。
PIRP Irp = IoXxx(...);
PIO_STACK_LOCATION Stack = IoGetNextIrpStackLocation(Irp);
ObReferenceObject(FileObject);
Stack->FileObject = FileObject;
IoCallDriver(DeviceObject, Irp);
ObDereferenceObject(FileObject);
IoGetDeviceObjectPointer()
执行一些步骤来定位返回的两个指针:
(1) 使用 ZwOpenFile()
打开一个命名的 device object
,它将引发 object manager
建立一个 file object
和发送 IRP_MJ_CREATE
到目标设备,ZwOpenFile()
返回 file handle
(2) 调用 ObReferenceObjectByHandle()
得到代表 file handle
的 FILE_OBJECT
结构地址,这个地址以 FileObject
返回。
(3) 调用 IoGetRelatedDeviceObject()
得到被 FileObject
引用的 DEVICE_OBJECT
结构地址,这个地址以 DeviceObject
返回。
(4) 调用 ZwClose()
关闭 Handle
5.2.3 Dispatch routine
职责
一个 Dispatch routine
的原型,看起来像下面:
NTSTATUS DispatchXxx(PDEVICE_OBJECT fdo, PRIP Irp)
{PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;...return STATUS_Xxx;
}
1.你通常需要访问当前 stack location
去检测参数或都检查 minor
功能号
2.你通常也需要访问你建立的 device extension
结构(在 AddDevice()
时候初始化的)。
3.最后要返回到 IoCallDriver()
调用上。传送一个 NTSTATUS
值。
>>> IRP
的完成
完成一个 IRP
必须填允 IRP
的 IoStatus
域内的 Status
与 Information
值,然后调用 IoCompleteRequest()
函数。
这个 Status
值是在 NTSTATUS.h
文件里定义的 status code
之一。而 Information
值依赖于 IRP
的类型而定,大多时候当 IRP
失败后Information
设置为 0
当 IRP
引发数据的传送操作,通常设置 Information
值为传送的字节数。
IRP(I/O Request Package)详解相关推荐
- IIS负载均衡-Application Request Route详解第三篇:使用ARR进行Http请求的负载均衡(上)...
IIS负载均衡-Application Request Route详解第三篇:使用ARR进行Http请求的负载均衡(上) 在前两篇文章中,我们已经讲述如何配置与安装ARR,从本篇文章开始,我们将重点的 ...
- IIS负载均衡-Application Request Route详解第一篇: ARR介绍
IIS负载均衡-Application Request Route详解第一篇: ARR介绍 说到负载均衡,相信大家已经不再陌生了,本系列主要介绍在IIS中可以采用的负载均衡的软件:微软的Appli ...
- IIS负载均衡-Application Request Route详解第六篇:使用失败请求跟踪规则来诊断ARR
失败请求跟踪规则(FailedRequest Tracing Rules)是IIS7中对请求处理进行诊断的强大的工具.我们本篇文章将会带领大家一步步的来配置失败请求跟踪规则,并且告诉大家如何使用这些信 ...
- IIS负载均衡-Application Request Route详解第五篇:使用ARR来配置试点项目
看到本篇的题目,大家可能感到有点奇怪!下面,我们就来看看这到底是什么意思. 大家可能遇到过这样的一种情况:希望根据某些请求用户的特性,将用户的请求导向不同的站点(请大家这里区分"亲缘性&qu ...
- IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构
本篇的主要目的是带领大家一起来使用ARR来实现一个三层部署架构.这里的三层部署架构主要是由:服务层,应用程序服务器层已经数据层实现.如下图所示: 每次一提到"层"这个字的时候,似乎 ...
- IIS负载均衡-Application Request Route详解第三篇:使用ARR进行Http请求的负载均衡
在前两篇文章中,我们已经讲述如何配置与安装ARR,从本篇文章开始,我们将重点的来讲述如何在使用ARR进行负载均衡. 本篇文章的目的主要是一步步的带领大家如何配置和使用ARR来进行Http请求的负载均衡 ...
- IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm
自从本系列发布之后,收到了很多的朋友的回复!非常感谢,同时很多朋友问到了一些问题,有些问题是一些比较基本的问题,由于时间的缘故,不会一一的为大家回复,如果有不明白的,希望大家勤自学!本系列虽然不难,但 ...
- IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm(转载)
IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm 自从本系列发布之后,收到了很多的朋友的回复!非常感谢,同时很多朋友问到了一些问题,有些问 ...
- request.getContextPath详解
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+ ...
最新文章
- Kdtree(K-dimension tree)学习
- winform 监听http_Winform HttpListener监听有关问题
- 安卓菜单选项 Popup_Menu / Context_Menu / Option_Menu
- Codeforces 1246D/1225F Tree Factory (构造)
- 12月中国域名服务商Top20市场份额解析(图)
- 持续集成、持续交付(CI/CD)开篇,先来唠唠嗑
- 八年级计算机考操作试题,八年级计算机会考必看试题!!!!!!
- mssql-sqlserver入门必备知识收集
- AltTab 把 Windows 的 Alt+Tab 功能带到 macOS
- ctf 选择题 题库_看雪CTF题库平台 | 赛练结合,助你夺冠!
- 使用python实现深度神经网络--学习笔记
- 联想服务器如何恢复预装系统,Thinkcentre E73 E63z等预装Win7系统如何恢复出厂系统...
- Mutual Component Convolutional Neural Networks for Heterogeneous Face Recognition阅读笔记
- 从本质出发理解掌握三大坐标系下的三大方程(三)--旋度公式
- setex php,python redis setex可以设value为list或者其他数据结构吗?
- iOS中制作一张水印图片
- go实现dgraph的各种操作
- 巧用order实现列表排序
- MacBook苹果电脑在充电中无法指纹解锁解决办法
- 完全平方数(c++基础)