阅读:2075回复:9
请教CcPinRead问题
在使用CcPinRead时,这个函数和CcUnpinData是对应的,现在的问题是对同一个FileObject,调用CcPinRead可以嵌套吗?
也就是能按这个顺序调用吗? 1.CcPinRead 2.CcPinRead/CcMapData 3.CcSetDirtyPinnedData第2步的CcPinRead 4.CcSetDirtyPinnedData第1步的CcPinRead 5.CcUnpinData第2步 6.CcUnpinData第1步 还是步能嵌套必须一对一的调用,即 1.CcPinRead 2.CcSetDirtyPinnedData 3.CcUnpinData 4.CcPinRead/CcMapData 5.CcSetDirtyPinnedData 6.CcUnpinData 以上如果是CcMapData则不调用CcSetDirtyPinnedData 还有我重新设置了FileSize,并且新设置的长度大于原来的长度,但调用CcPinRead时不会触发出Read的irp,也就是得到的还是老的cache中的数据,新的数据不会更新到cache中,为什么? 我查了一天,就是看不出原因! |
|
|
沙发#
发布于:2007-08-09 11:36
顶你个成长中的高手
|
|
板凳#
发布于:2007-08-10 11:00
自己顶一下
|
|
|
地板#
发布于:2007-08-10 15:00
Cache的四个接口
\begin{itemize} \item File Stream Manipulation Functions \item Copy Interface \item MDL Interface \item Pinning Interface \end{itemize} 注意:Cache管理器的Pin接口和另外两个接口:Copy接口以及MDL接口不能 同时使用。 重要:Cache管理器并解释被缓存的数据内容,它只是理解File Object以及 相关的Stream对象。 Cache管理器的客户类型:文件系统驱动、过滤器驱动、网络文件重 定向器、网络文件服务器。 HSM:Hierarchical Storage Management。 FILE\_OBJECT中大部分字段是由IO管理器负责维护,但有几个例外: FsContext指向一个CommonFCBHeader结构,简称FCB,也就是Unix系统 中的vnode结构,或许就是DOS下的FCB。注意FILE\_OBJECT是Per handle的,而FCB则是per file stream的。 一个重要的结构: \begin{verbatim} // // The following structure is pointed to by the SectionObject // pointer field // of a file object, and is allocated by the various NT file systems. // typedef struct _SECTION_OBJECT_POINTERS { PVOID DataSectionObject; PVOID SharedCacheMap; PVOID ImageSectionObject; } SECTION_OBJECT_POINTERS; typedef SECTION_OBJECT_POINTERS *PSECTION_OBJECT_POINTERS; \end{verbatim} 和FCB一样,这也是一个per file stream的对象,其三个成员都是 Cache管理器的私有结构,甚至在IFSKits中都没有公开。 \section{Cache Map} 一个复杂的对象,结构未知! 理解Cache子系统的关键在于了解Io管理器、文件系统、Cache管理器、 Memory管理器之间的关系,用户读写文件时首先经过Io管理器,Io管 理器视情况而定可能会直接向文件系统发出请求,也可能绕过文件系统 直接和Cache管理器打交道,对于后者来说,Cache管理器将利用Memory 管理器的功能实现数据的读写----事实上只是一个简单的拷贝。 问题:如果Io管理器向文件系统发出请求,那么是不是文件系统(在做了必要 的初始化工作之后)一定会回头调用Cache管理器? \section{Virtual Address Control Block} Cache管理器为每个File Stream开了一个或者多个窗口,每个窗口的大小都是固定的, 记得是256KB。这些窗口用VACB来管理。 看上去Private Cache Map只是为了将同一个File Stream的多个File Object串起来, 因为Cache管理器为了Unmap一个VACB,必须通知每个 File Object,所以这样一个 链表是有必要的。 Cache Manager的Fast IO看上去是NT的开发小组在最后时刻发现系统 性能问题后草草设计出来的,虽然现在这个接口已经发展的很成熟了, 但总的来说还是有些不好理解。 每个Handle都必须调用Cache管理器初始化缓存。 文件系统提供给Cache管理器的回调接口倒是很简单: \begin{verbatim} typedef struct _CACHE_MANAGER_CALLBACKS { PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite; PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite; PACQUIRE_FOR_READ_AHEAD AcquireForReadAhead; PRELEASE_FROM_READ_AHEAD ReleaseFromReadAhead; } CACHE_MANAGER_CALLBACKS, *PCACHE_MANAGER_CALLBACKS 初始化CacheMap: void CcInitializeCacheMap ( IN PFILE_OBJECT PtrFileObject, IN PCC_FILE_SIZES FileSizes, IN BOOLEAN PinAccess, IN PCACHE_MANAGER_CALLBACKS CallBacks, IN PVOID LazyWriterContext ); \end{verbatim} LazyWrite和ReadAhead是Cache管理器完成的,但是Cache管理器在 执行这些任务时,必须获得文件系统的支持,上面的Callback参数 就是文件系统提供给Cache管理器的许可证,Cache管理器会在 LazyWrite和ReadAhead的时候调用这些回调函数。这些回调的主要 任务通常是同步。 LazyWriterContext这个名字取的不好,实际上这个参数同时用作 LazyWriter和ReadAhead的上下文参数,通常这个参数就是Context Control Block,一个和File Object并列的对象,不过后者是Io 管理器创建的而CCB则是文件系统创建的,另外,通常这个指针会 保存在FileObject对象的Context2字段中,这应该算是一种文化 了吧我想。 注意这个函数没有返回值,调用者必须作好准备接受任何可能产生 的例外。 \section{Copy接口} 文件系统在处理Read请求时,可以调用Cache管理器的Copy接口, 如果要copy的数据不在物理内存中,则会产生页面错误,将由 Memory Manager调用文件系统将数据从外设(磁盘或者网络服 务器)拷贝到物理内存中,也就是说,文件系统将被递归的调用。 写数据的时候也可能会需要等待,如果写的内容不是硬件扇区 对齐的,则可能需要执行读操作,这样就有可能造成Blocking; 另外写数据需要空闲物理内存页面,如果没有的话则需要执行 LazyWrite并分配新的内存,这也会造成阻塞。 \emph{CcCanIWrite}\\ 这个函数很有意思,由于在Write接口中的函数有可能会由于空闲 页面不足(即Dirty Page过多)造成等待,所以可以用这个函数 测试一下当前能否执行不阻塞的写操作,这个测试是建议性的, 如果测试完了立刻有个别的家伙又写了一堆东西,则随后的写操作 可能还是会阻塞,不过由于这个竞争情况不会影响程序的正确性, 只是会导致阻塞,所以通常不需要关心。 \emph{CcDeferWrite}\\ 请求Cache管理器调度一个事件,在能够进行写操作的时候执行 一个回调,通常就是文件系统的写入口函数。 \section{Pin接口} 和Copy接口不同,Copy接口始终是使用FileObject和Offset来 寻址Cache管理器管理的内存,而不是直接用指针,而Pin接口 则提供了Pin功能,这样文件系统就可以把Cache管理器管理的 内存'钉'在内存里,随后就可以用指针来寻址了。 Pin需要经过两个步骤:Map、Pin。 CcMapData\\ CcPinMappedData\\ CcPinRead\\ CcSetDirtyPinnedData\\ CcPreparePinWrite\\ 提供这个函数可以认为是一种优化措施,和CcPinRead相比,如果 参数中指定的区域刚好在Page边界上,则Cache管理器不会从二级 存储器中读入该页,因此这个函数返回的缓冲区不能用来读取数据。 CcUnpinData/CcUnPinDataForThread。 注意在Pin期间,在调用者线程上下文中不会有IO发生,所有的IO 都是异步的。 \section{MDL接口} CcMdlRead\\ CcMdlReadComplete\\ CcPrepareMdlWrite\\ CcMdlWriteComplete\\ CcMdlRead和CcPrepareMdlWrite会返回一个MDL链表,这个链表在 对应的Complete函数中释放,所以这两对函数必须成对调用,以 避免内存泄漏。 \section{Cache管理器和VMM的交互} 初始化CacheMap时调用MmCreateSection,扩展文件流时调用 MmExtendSection。 这里有很多在DDK中都没有公开的函数,倒是作为系统服务导出给 ntdll了,例如MmCreateSection大致等于ZwCreateSection。 从工作集管理上看,Cache管理器对VMM来说是一个普通的客户, 即它和普通进程一样,其Working Set要经过VMM的修剪。 \section{预读取模块} \section{后写模块} \chapter{文件子系统} 文件系统不能区分两种请求,一种是应用程序调用产生的读写 请求,一种是由于Cache管理器进行Copy时的页面故障导致VMM向 文件系统发出的读写请求。 \section{几种重要的同步对象} \begin{itemize} \item FSD锁(MainResource) \item PagingIoResource \item 和文件流相关的字节范围锁 \item 机会锁(oplock) \end{itemize} [返回顶部] -------------------------------------------------------------------------------- 2004-04-22 20:21:59 主题: 内核对象和执行体对象 内核和执行体具有一些同名对象,例如Event、Mutant、Process、Thread等, 通常的说法是执行体对象是对零个或者多个内核对象的封装,这个说法不妨 可以再直白一些: \begin{verbatim} class EPROCESS : public KPROCESS, public OBJECT_HEADER { }; class KPROCESS : public DISPATCHER_HEADER { }; \end{verbatim} 写成这样,为什么说Windows的进程对象(以及线程对象,道理类似)都是 可以等待的,应该就很清楚了吧:因为它继承了DISPATCH\_HEADER对象,而 后者正是实现可等待对象(用Windows自己的话,大概应该叫`可调度对象'吧) 的关键。 也就是说,在一个执行体进程对象中,包含了一个用来给内核管理用的 KPROCESS对象,一个用来使进程对象能够参与同步的DISPATCHER\_HEADER 头部对象,和一个给对象管理器用来实施管理的OBJECT\_HEADER结构。 其它执行体对象,例如Event、FileObject等都可以进行类似分析。 |
|
地下室#
发布于:2007-08-10 17:20
lsxredrain兄,你是一个负责任,乐于助人的人
这个坛子,向你这样的朋友不多了 |
|
5楼#
发布于:2007-08-10 18:39
增加了FsRtlEnterFileSystem/FsRtlExitFileSystem就好了
可能没有加这个时执行中途被交换出去了 |
|
|
6楼#
发布于:2007-08-10 19:06
|
|
7楼#
发布于:2007-08-10 20:15
他这个是文件过滤驱动?
|
|
|
8楼#
发布于:2007-08-10 22:04
好象不是过滤驱动,是文件系统,
|
|
9楼#
发布于:2007-08-11 16:34
那看fastfat的源代码一样的
|
|
|