文件系统Minifilter驱动(九)

来源:互联网 发布:手机壳定制软件 编辑:程序博客网 时间:2024/04/30 02:52

六、决定一个I/O操作的Buffering方法 

与设备驱动一样,文件系统负责在用户模式应用程序和一个系统的设备之间传输数据.操作系统提供了以下三种方法访问数据buffer: 

· buffered I/O方法中,I/O管理器从非分页池中为操作分配一个系统buffer.I/O管理器在发起该I/O操作的上下文中,从这个系统buffer中复制数据到应用程序的user buffer中,反之亦然.

· direct I/O方法中,I/O管理器探测并锁住user buffer.然后它创建一个MDL来映射被锁的buffer.I/O管理器在发起I/O操作的线程上下文中访问该buffer.

· neither I/O中,I/O管理器既不分配一个系统buffer也不锁住或映射 user buffer.而是简单地把buffer的原始用户空间虚拟地址传给文件系统栈.驱动负责确保它们正执行在发起线程的上下文中且buffer地址是有效的.

Minifilter驱动必须在试图使用这些地址之前验证其在用户空间中是否有效. I/O管理器和filter管理器不会验证这样的地址也不会验证内含在要被传给minifilter驱动的buffer中的指针.

所有标准的微软文件系统对大多数I/O处理都使用NEITHER I/O.

更多关于buffering方法的信息,参考Methods for Accessing Data Buffers

对IRP-I/O操作来说,所使用的buffering方法是操作指定的且由以下要素决定: 

· 正被执行的I/O操作的类型 

· 文件系统卷的DEVICE_OBJECT 结构的成员Flags的值 

· 对IOCTL和FSCTL操作来说,当IOCTL或FSCTL被定义时,被传给CTL_CODE宏的参数TransferType 的值 

有buffer的Fast I/O操作总是用NEITHER I/O. 

文件系统callback操作没有buffer.

本节包括: 

1.可以是IRP-I/O或Fast I/O的操作 

以下类型的操作可以是基于IRP或fast I/O的操作: 

· IRP_MJ_DEVICE_CONTROL. (注意IRP_MJ_INTERNAL_DEVICE_CONTROL总是基于IRP的.) 

· IRP_MJ_QUERY_INFORMATION. 如果FileInformationClass参数为FileBasicInformation、FileStandardInformation或FileNetworkOpenInformation则这个操作可以是fast I/O. 

· IRP_MJ_READ. Minifilter驱动可以在FLT_OPERATION_REGISTRATION结构中设置FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO标记来避免收到fast I/O IRP_MJ_READ操作和cached 基于IRP的读. 

· IRP_MJ_WRITE. Minifilter驱动可以在FLT_OPERATION_REGISTRATION结构中设置FLTFL_OPERATION_REGISTRATION_SKIP_CACHED_IO标记来避免收到fast I/O IRP_MJ_WRITE操作和cached基于IRP的写. 

当所有这些操作都是fast I/O操作时,它总是使用NEITHER I/O,即使等价的基于IRP的操作使用不同的buffering方法.

当IRP_MJ_DEVICE_CONTROL是一个fast I/O操作时,它总是使用NEITHER I/O而不管IOCTL的传输类型是什么.

尽管IRP_MJ_LOCK_CONTROL可以是一个基于IRP或fast I/O的操作,但它没有buffer. 

2. 遵从Device Object Flags的IRP-I/O操作

以下IRP-I/O操作所使用的buffering方法由文件系统卷的DEVICE_OBJECT 结构的成员Flags的值决定

· IRP_MJ_DIRECTORY_CONTROL 

· IRP_MJ_QUERY_EA 

· IRP_MJ_QUERY_QUOTA 

· IRP_MJ_READ 

· IRP_MJ_SET_EA 

· IRP_MJ_SET_QUOTA 

· IRP_MJ_WRITE 

在Flags成员中使用的DO_BUFFERED_IO和DO_DIRECT_IO标记的使用如下: 

· 如果设置了DO_BUFFERED_IO,则操作使用buffered I/O. 

· 如果设置了DO_DIRECT_IO且没有设置DO_BUFFERED_IO,则操作使用direct I/O. 

· 如果两个标记都没有设置,则操作使用NEITHER I/O. 

更多设备对象标记的信息,参考DEVICE_OBJECT and Initializing a Device Object

注意IRP_MJ_READ和IRP_MJ_WRITE可以是基于IRP或fast I/O的操作.当它们基于IRP时,buffering方法由以上描述的设备对象标记决定.当它们是fast I/O,它们总是使用neither I/O.更多关于可以是基于IRP或fast I/O的操作的I/O操作的信息,参考可以是IRP-I/O或Fast I/O的操作

3.总是使用buffered I/O的IRP-I/O操作 

以下IRP-I/O操作总是使用buffered I/O,而不管文件系统卷的DEVICE_OBJECT结构的成员Flags的值是什么

· IRP_MJ_CREATE (EaBuffer参数

· IRP_MJ_QUERY_INFORMATION 

· IRP_MJ_QUERY_VOLUME_INFORMATION 

· IRP_MJ_SET_INFORMATION 

· IRP_MJ_SET_VOLUME_INFORMATION 

注意IRP_MJ_QUERY_INFORMATION也可以是一个fast I/O操作.当它是一个fast I/O操作时,它用neither I/O.更多关于可以是基于IRP或fast I/O的操作的信息,参考可以是IRP-I/O或Fast I/O的操作

4. 总是使用Neither 的IRP-I/O操作 

以下IRP-I/O操作总是使用neither I/O,而不管文件系统卷的DEVICE_OBJECT结构的成员Flags的值是什么

· IRP_MJ_PNP 

· IRP_MJ_QUERY_SECURITY 

· IRP_MJ_SET_SECURITY 

· IRP_MJ_SYSTEM_CONTROL 

5.基于IRP的IOCTL和FSCTL操作

以下IRP-I/O操作所使用的buffering方法与IOCTL或FSCTL中定义的传输类型相匹配: 

· IRP_MJ_DEVICE_CONTROL 

· IRP_MJ_FILE_SYSTEM_CONTROL 

· IRP_MJ_INTERNAL_DEVICE_CONTROL 

传输类型是在CTL_CODE宏的参数TransferType 中指定的. 要获得一个给定的IOCTL或FSCTL的传输类型,使用以下宏: 

#define METHOD_FROM_CTL_CODE(ctrlCode)         ((ULONG)(ctrlCode & 3))

这个宏的返回值为以下之一: 

#define METHOD_BUFFERED                 0
#define METHOD_IN_DIRECT                1
#define METHOD_OUT_DIRECT               2
#define METHOD_NEITHER                  3

更多关于CTL_CODE宏的信息,参考Defining I/O Control Codes

注意IRP_MJ_DEVICE_CONTROL也可以是一个fast I/O操作.当它是一个fast I/O操作时,它总是使用neither I/O,而不管IOCTL的传输类型是什么.更多关于IRP_MJ_DEVICE_CONTROL什么时候可以是一个fast I/O操作的信息,参考可以是IRP-I/O或Fast I/O的操作

6. 没有buffer的IRP- I/O操作 

以下IRP-I/O操作没有buffer因此也没有buffering方法: 

· IRP_MJ_CREATE_MAILSLOT 

· IRP_MJ_CREATE_NAMED_PIPE 

· IRP_MJ_LOCK_CONTROL 

七、访问一个I/O操作的User Buffers

一个I/O操作的FLT_PARAMETERS结构包含操作的操作指定的参数,包括buffer地址和操作中使用的一切buffer的MDL. 

对IRP-I/O操作来说,它的buffer可以通过使用以下来指定: 

· 仅MDL (一般为分页I/O) 

· 仅Buffer地址 

· Buffer地址和MDL 

对fast I/O操作来说,只有用户空间buffer地址是指定的. 有buffer的Fast I/O操作总是使用neither I/O因此没有MDL参数. 

下文提供了在minifilter驱动的pre-oper和post-oper callback例程中处理基于IRP和fast I/O的操作的buffer地址和MDL的指导方针: 

1.在pre-oper callback例程中访问User Buffers 

Minifilter驱动的pre-oper callback例程 应按如下方式来对待IRP-I/O操作中的buffer: 

· 检查buffer是否存在一个MDL. MDL的指针可以在操作的参数MdlAddressOutputMdlAddress中找到. (Minifilter驱动也可以调用FltDecodeParameters来查询MDL指针.) 

· 若此buffer存在一个MDL,就调用 MmGetSystemAddressForMdlSafe来获得buffer的系统地址,然后用这个地址来访问buffer.

· 若此buffer没有MDL,就用buffer地址来访问buffer.要确保一个用户空间的buffer地址是有效的,minifilter驱动必须使用像ProbeForRead 或ProbeForWrite这样的例程,在try/except块中封装所有的buffer引用. 

Pre-oper callback例程应按如下方式来对待fast I/O操作中的buffer: 

· 使用buffer地址访问这个buffer (因为fast I/O操作没有MDL). 

· 要确保一个用户空间的buffer地址是有效的, minifilter驱动必须使用像ProbeForRead 或ProbeForWrite这样的例程,在try/except块中封装所有的buffer引用.

对可以是fast I/O或基于IRP的操作来说,所有的buffer引用都应被封装到try/except块中. 尽管你不必在使用buffered I/O的IRP-I/O操作中这样封装这些引用,但try/except块是一中安全预防措施

2.在post-oper callback例程中访问User Buffers

Minifilter驱动的post-oper callback例程 应按如下方式来对待IRP-I/O操作中的buffer: 

· 检查buffer是否存在一个MDL. MDL的指针可以在操作的参数MdlAddressOutputMdlAddress中找到. (Minifilter驱动也可以调用FltDecodeParameters来查询MDL指针.)

· 若此buffer存在一个MDL,就调用 MmGetSystemAddressForMdlSafe来获得buffer的系统地址,然后用这个地址来访问buffer. (MmGetSystemAddressForMdlSafe可以在 IRQL <= DISPATCH_LEVEL调用.) 

· 若此buffer没有MDL,就用FLT_IS_SYSTEM_BUFFER宏检查此操作有没有设置系统buffer标记. 

如果FLT_IS_SYSTEM_BUFFER宏返回TRUE,则此操作使用了buffered I/O,且在DISPATCH_LEVEL可安全地访问该buffer. 

如果FLT_IS_SYSTEM_BUFFER宏返回FALSE,则在IRQL = DISPATCH_LEVEL不可以安全地访问该buffer. 如果post-oper callback 例程可以在DISPATCH_LEVEL调用,它必须调用 FltDoCompletionProcessingWhenSafe来pend这个操作直到它可以在IRQL <= APC_LEVEL被处理.被FltDoCompletionProcessingWhenSafeSafePostCallback参数指向的callback例程应首先调用FltLockUserBuffer来锁住buffer,然后调用MmGetSystemAddressForMdlSafe获得该buffer的系统地址. 

Post-oper callback例程应按如下方式来对待fast I/O操作中的: 

· 使用buffer地址访问这个buffer (因为fast I/O操作没有MDL). 

· 要确保一个用户空间的buffer地址是有效的, minifilter驱动必须使用像ProbeForRead 或ProbeForWrite这样的例程,在try/except块中封装所有的buffer引用. 

· 一个fast I/O操作的post-oper callback例程被担保会在正确的线程上下文中被调用. 

· 一个fast I/O操作的post-oper callback例程被担保会在IRQL <= APC_LEVEL被调用,因此它可以安全地调用像FltLockUserBuffer这样的例程

对可以是fast I/O或基于IRP的操作来说,所有的buffer引用都应被封装到try/except块中. 尽管你不必在使用buffered I/O的IRP-I/O操作中这样封装这些引用,但try/except块是一中安全预防措施

原创粉丝点击