IRP_MJ_SET_INFORMATION有个特殊的参数:AdvanceOnly,DDK中说明如下:
实际实现中,此参数只针对FileEndOfFileInformation才有意义。FileEndOfFileInformation case是用来处理文件数据大小的,即更改文件数据长度。但当AdvanceOnly为TRUE的时候,情形并不如此,此时的真实目的是更新ValidDataLength (VDL),并不是EndOfFile,这是最容易让人误解的地方。
下面是一个典型的调用实例,堆栈分析如下 (XP, i386):
0: kd> kb
ChildEBP RetAddr Args to Child
ba4e3bbc b16dfd58 89a462c0 899f8ad8 ba4e3c0c Ext2Fsd!Ext2SetFileInformation+0x2a2
ba4e3bcc b16dfe67 89a462c0 0b2b27d2 899f8ad8 Ext2Fsd!Ext2DispatchRequest+0x9a
ba4e3c0c 804f0095 898d4af8 88b66c40 88b66c40 Ext2Fsd!Ext2BuildRequest+0x89
ba4e3c1c b9ed709e 8988b008 899de848 00000000 nt!IopfCallDriver+0x31
ba4e3c48 804f0095 899f8ad8 88b66c40 88b66c40 fltMgr!FltpDispatch+0x152
……
ba4e3cb4 804f0095 89a8ead8 88b66c40 89a8ead8 fltMgr!FltpDispatch+0x11f
ba4e3cc4 804e2f43 00000000 88cbd008 806e59f0 nt!IopfCallDriver+0x31
ba4e3cf8 804e59aa 88ccd4f8 ba4e3d20 80559690 nt!CcSetValidData+0xa5
ba4e3d34 804e8081 89e31098 80564720 89e31998 nt!CcWriteBehind+0x258
ba4e3d7c 805389bd 89e31098 00000000 89e31998 nt!CcWorkerThread+0x12f
ba4e3dac 805cf84c 89e31098 00000000 00000000 nt!ExpWorkerThread+0xef
ba4e3ddc 8054632e 805388ce 00000000 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
可以看出,调用者是Lazy-writer线程。CcWriteBehind将dirty cache写入磁盘后会调用CcStValidData来更新当前文件的ValidDataLength。Cache Manager在每个文件的SHARED_CACHE_MAP中在保存着此文件最大的ValidDataLength (变量ValidDataGoal,由脏页的最大偏移计算出),并在每次写入cache后告知文件系统。
NTFS文件系统中有VDL的概念,但FAT及EXT2都没有,只有AllocationSize及FileSize描述。Ext2Fsd是直接将VDL等同于FileSize来处理的。