读懂常见IRP:IRP_MJ_CLEANUP\IRP_MJ_CLOSE\IRP_MJ_CREATE

读懂常见IRP:IRP_MJ_CLEANUP\IRP_MJ_CLOSE\IRP_MJ_CREATE

根据MSDN翻译的,网上许多兄弟问此类的问题,解答很少。希望本文能有所帮助。

IRP_MJ_CLEANUP

保持进程定义上下文信息的驱动器,必须在DispatchCleanup中包含cleanup请求。

何时发送:
收到IRP_MJ_CLEANUP意味着请求的目标设备与目标文件的句柄相关(也可能因为io请求后没有释放)

入参:

出参:

操作:
该IRP在关闭 file  object 句柄的进程上下文中发送。因此,驱动器应该释放进程上下文中所指定的资源,比如之前驱动器锁定或映射的user memory等。
如果驱动器的 device objects 状态是exclusive,则该device是独占性的,一次只能为一个线程服务。驱动器必须结束当前目标 device object 队列中的所有IRP,并设置其I/O status block为STATUS_CANCELLED。
另外,驱动器只是需要取消并结束与待释放的file object句柄相关的IRP队列成员。(指向file object的指针位于驱动器IRP IO_STACK_LOCATION的FileObject成员中。)取消队列中的IRP后,驱动器结束了clear up IRP操作,并将自身的I/O status block置为STATUS_SUCCESS。
//------------------------------------------------------------------------------------------
IRP_MJ_CLOSE

驱动器必须在DispatchClose中包含关闭请求和驱动器的可能发生的异常,因为该驱动器只能通过关闭系统来卸载设备,保持了系统分页文件的的磁盘驱动器就属于这类驱动器。具有该类特性驱动器支持动态卸载。

何时发送:
收到IRP_MJ_CLOSE请求意味着与目标device object相关的file object句柄已经关闭或释放。所有的外部I/O请求都已结束或取消。

入参:

出参:

操作:
很少有设备会设置IRP的status block为STATUS_SUCCESS结束关闭请求。驱动器如何处理关闭请求取决于其设计。通常,驱动器在收到IRP_MJ_CREATE后会undo自己的操作结果。device object为exclusive的驱动器,比如串行驱动器,在收到该请求后也可能会reset硬件。
IRP_MJ_CLOSE不是在关闭了file object句柄的进程上下文中发送的。如果驱动器必须释放进程指定的资源,比如驱动器之前锁定或映射的user memeory等,就会对IRP_MJ_CLEANUP请求做同样的响应。
//------------------------------------------------------------------------------------------
IRP_MJ_CREATE

kernel-mode驱动器必须在DispatchCreate或DispatchCreateClose中提出创建请求。

何时发送:
收到该请求意味着user-mode保护的子系统(可能代表的是某个应用程序),请求一个file object句柄,该局并代表特定的目标device object,或者是较高级别的驱动器正在连接器device object到目标device object。

入参:

出参:

操作:
与IRP_MJ_CLOSE类似,对IRP_MJ_CREATE的相应取决与驱动器的设计,很少有驱动器会设置IRP的I/O status block为STATUS_SUCCESS。带有pageable-image单元的驱动器,像系统串行驱动器,会通过映射自身的page-out代码,来为那些尝试打开设备进行I/O操作的user-mode线程提供资源。

//------------------------------------------------------------------------------------------
IRP_MJ_DIRECTORY_CONTROL

何时发送:
IRP_MJ_DIRECTORY_CONTROL请求是由I/O管理器和其他操作系统组件(比如kernel-mode驱动器)发送的。当user-mode程序调用ReadDirectoryChangesW、FindNextVolumeMountPoint或者kernal-mode componenet调用ZwQueryDirectoryFile时,会发送该请求。

操作:文件系统驱动器
文件系统驱动器通过检查监控程序code来判断判断执行哪一个目录控制操作。有效的监控程序codes:
IRP_MN_NOTIFY_CHANGE_DIRECTORY
请求告知目录变更。通常文件系统驱动器会将此IRP放到私有的队列中,而不是立即进行满足该请求。 当目录发生变更时,文件系统驱动器执行通知目录变更操作,出队,结束该IRP。
IRP_MN_QUERY_DIRECTORY
目录查询请求。消息类型因文件系统而异,通常包括以下几种:
FileBothDirectoryInformation
FileDirectoryInformation
FileFullDirectoryInformation
FileIdBothDirectoryInformation
FileIdFullDirectoryInformation
FileNamesInformation
FileObjectIdInformation
FileReparsePointInformation

注意:FileQuotaInformation类已不再使用,用IRP_MJ_QUERY_QUOTA代替。
执行之后,结束IRP。

操作:文件系统过滤驱动器
过滤驱动器将该IRP向栈上的下一层驱动器传递。
//------------------------------------------------------------------------------------------
IRP_MJ_QUERY_INFORMATION

何时发送:
IRP_MJ_QUERY_INFORMATION请求的发送和IRP_MJ_DIRECTORY_CONTROL类似,是由I/O管理器和其他操作系统组件(比如kernel-mode驱动器)发送的。调用GetFileInformationByHandle或ZwQueryInformationFile时发送。

操作:文件系统驱动器
文件系统驱动器提取file object信息并进行解析,由此判断用户是打开一个文件还是打开一个目录,这样,驱动器处理查询并结束IRP。如果不能对信息进行提取解析,驱动器结束IRP,不处理查询。
可供查询的文件和目录信息因文件系统而异,通常包括如下几种:
FileAllInformation
FileAttributeTagInformation
FileBasicInformation
FileCompressionInformation
FileEaInformation
FileInternalInformation
FileNameInformation
FileNetworkOpenInformation
FilePositionInformation
FileStandardInformation
FileStreamInformation
ZwQueryInformationFile支持FileAccessInformation, FileAlignmentInformation, 和 FileModeInformation 类型,而无需向文件系统发送IRP_MJ_QUERY_INFORMATION请求,因为他们与文件系统无关。

操作:文件系统过滤驱动器
过滤驱动器将该IRP向栈上的下一层驱动器传递。
//------------------------------------------------------------------------------------------
IRP_MJ_QUERY_VOLUME_INFORMATION

何时发送:
IRP_MJ_QUERY_VOLUME_INFORMATION请求由I/O管理器发送。当user-mode程序调用GetDiskFreeSpace或GetFileType时会发送该请求。

操作:文件系统驱动器
文件系统驱动器通过对file object进行提取和解码,判断目标device object是不是该文件系统的control device object。如果是,并且请求的是打开volume(或者打开volume上的object),文件系统驱动器会处理请求并结束IRP。如果不是,文件系统驱动器查询失败,结束IRP。
可供查询的volume信息类型因文件系统而异,通常有如下几种类型:
FileFsAttributeInformation
FileFsDeviceInformation
FileFsSizeInformation
FileFsVolumeInformation

操作:文件系统过滤驱动器
过滤驱动器将该IRP向栈上的下一层驱动器传递。
//------------------------------------------------------------------------------------------
IRP_MJ_READ

向系统传递数据的驱动器必须在DispatchRead或DispatchReadWrite中包含read请求,在此类驱动器上分层的higher-level驱动器也必须这样做。

何时发送:
在完成create请求的之后的时间域内发送。
可能由包含file object句柄(代表请求过从从该device传递数据的目标device object)的user-mode程序或win32组件发送。也可能由创建和设置read IRP的higher-level驱动器发送。

入参:
IRP中的驱动器I/O stack位置指示Parameters.Read.Length.传送多少byte数据。
有些驱动器通过Parameters.Read.Key对在device queue或驱动器管理的IRP内部队列中对read请求进行排序。有的驱动器通过Parameters.Read.ByteOffset(指示传送操作的offset)进行排序。

出参:
根据驱动器对device object Flag的是DO_BUFFERED_IO还是DO_DIRECT_IO,采用不同的方法传递数据:
The buffer at Irp->AssociatedIrp.SystemBuffer if the driver uses buffered I/O
The buffer described by the MDL at Irp->MdlAddress if the underlying device driver uses direct I/O (DMA or PIO)

操作:
接收到read请求之后,higher-level驱动器会通过为next-lower驱动器设置IRP中的I/O stack位置,或者为lower驱动器创建并设置附加的IRP。可以调用IoSetCompletionRoutine设置IoCompletion(在IRP输入中是可选的,但在driver-created IRP是必须的)。
接收到该请求之后,驱动器将器device传送给系统memory。结束IRP的过程中,驱动器将设置I/O stack block为传递的byte数量。
 
//------------------------------------------------------------------------------------------
IRP_MJ_SET_INFORMATION

何时发送:
IRP_MJ_SET_INFORMATION请求的发送和IRP_MJ_QUERY_INFORMATION、IRP_MJ_DIRECTORY_CONTROL类似,是由I/O管理器和其他操作系统组件(比如kernel-mode驱动器)发送的。调用SetEndOfFile或ZwSetInformationFile时发送。

操作:文件系统驱动器
文件系统驱动器提取file object信息并进行解析,由此判断用户是打开一个文件还是打开一个目录,这样,驱动器处理查询并结束IRP。
可供设置的文件、目录属性信息如下:
FileBasicInformation
FileDispositionInformation
FileLinkInformation (for file systems that allow cycles to be created in the directory hierarchy)
FilePositionInformation
FileRenameInformation
文件专有属性:
FileAllocationInformation
FileEndOfFileInformation
FileLinkInformation (for file systems, such as NTFS, that do not allow cycles to be created in the directory hierarchy)
FileValidDataLengthInformation

操作:文件系统过滤驱动器
过滤驱动器将该IRP向栈上的下一层驱动器传递。
//------------------------------------------------------------------------------------------
IRP_MJ_SET_INFORMATION*
IRP_MJ_SET_INFORMATION (Serial)

何时发送:
client通过set information请求改变串行设备上打开的文件结尾位置时发送。

//------------------------------------------------------------------------------------------
IRP_MJ_WRITE

向系统传递数据的驱动器必须在DispatchWrite或DispatchReadWrite中包含write请求,在此类驱动器上分层的higher-level驱动器也必须这样做。

何时发送:
成功结束creat请求的时间域内。
可能由包含file object句柄(代表请求过从从该device传递数据的目标device object)的user-mode程序或win32组件发送。也可能由创建和设置write IRP的higher-level驱动器发送。

入参:
IRP中的驱动器I/O stack位置指示Parameters.Write.Length.传送多少byte数据。
有些驱动器通过Parameters.Write.Key对在device queue或驱动器管理的IRP内部队列中对write请求进行排序。有的驱动器通过Parameters.write.ByteOffset(指示传送操作的offset)进行排序。
根据驱动器对device object Flag的是DO_BUFFERED_IO还是DO_DIRECT_IO,采用不同的方法传递数据:
The buffer at Irp->AssociatedIrp.SystemBuffer, if the driver uses buffered I/O
The buffer described by the MDL at Irp->MdlAddress, if the underlying device driver uses direct I/O (DMA or PIO)

出参:

操作:
接收到write请求之后,higher-level驱动器会通过为next-lower驱动器设置IRP中的I/O stack位置,或者为lower驱动器创建并设置附加的IRP。可以调用IoSetCompletionRoutine设置IoCompletion(在IRP输入中是可选的,但在driver-created IRP是必须的)。之后,驱动器通过IoCallDriver传递请求给next-lower驱动器。
接收到该请求之后,驱动器将数据从系统memory传递到自身的device。结束IRP的过程中,驱动器将设置I/O stack block为传递的byte数量。
//------------------------------------------------------------------------------------------
IRP_MJ_WRITE*
分段写入,提供Offset,每次写入65536字节。

你可能感兴趣的:(读懂常见IRP:IRP_MJ_CLEANUP\IRP_MJ_CLOSE\IRP_MJ_CREATE)