时钟在敲

同样的是老歌,苏联的老歌曲显得更耐听一些,反观我们的,曲子很好,旋律也美,但词却怎么也唱不出口了,动不动就党啊毛啊的,太露骨。跟时代跟得太紧,必然会被时代抛弃!

时钟在敲,心儿在跳,这正时时候,送去欢笑;时钟在敲,心儿在跳,这正是时候,将错误抛掉 ……

无厘头

凡是不确定的东西,你都会觉得难,但其实它可能根本就是无厘头!今天就遇到两件无厘头的事:

第一件是个很无厘头的数据损坏的bug。说它是无厘头,是因为还没搞清楚它为什么会发生,虽然找到了解决方案并且解决方案非常简单。问题大体如下:针对cached i/o,如果写数据超出文件大小,我们会为此文件再分配空间,然后直接调用CcCopyWrite交给Cache Manager来处理就行。这里会涉及文件大小的更改,问题就出在这里。以前的版本是在CcCopyWrite之前就直接将文件大小改好了,数据写入一切正常。后来觉得不妥当,遂改到调用CcCopyWrite之后根据返回结果来更改文件大小,结果就发生了数据的损坏。但研究来研究去,并没有发现CcCopyWrite函数有对文件大小有什么判断。

数独

第二件是一个数独游戏。以前也摆过这道题,但因为不确定性太多,无法下子,然后就不了了之。今天又摆上了,到后面只剩下了1,3,5和8,可能的摆法 很多,就随便摆了摆,结果就通了。呵呵,原来是怎么摆都成,而不是就只有唯一的一个确定的方案!这道题实际上是第一题,应该是最容易的。但我当初玩时却在想,为什么第一题这么难,倒是后面的比较容易,难就难在太纠结于不确定上面了。

FastIo

针对FastIoRead及FastIoWrite的实现,很多文件系统驱动都简单地调用系统提供的File System Runtime Routine: FsRtlCopyRead和FsRtlCopyWrite。

但这样做会有一个隐患,以Ext2Fsd来说,实际的文件大小是存储在inode.i_size中的,不是在FSRTL_COMMON_FCB_HEADER中(或FSRTL_ADVANCED_FCB_HEADER,前者超集)。Cache Manager内部只会处理FSRTL_COMMON_FCB_HEADER中的FileSize,从而导致Fcb中的FileSize和内部的inode.i_size大小不一致。这个 bug还是测试在EXT2卷上用DDK编译/build程序时发现的。

解决办法就是实现自己的FastIoWrite,如果写请求超出文件大小则拒绝此请求,然后走正常的IRP流程。其实,结合上篇blog: AdvanceOnly- FileEndOfFileInformation,还有另外一种方案,即在处理FileEndOfFileInformation w/ AdvanceOnly 时来更新内部的inode.i_size至最新大小,但此方法有待验证。

AdvanceOnly – FileEndOfFileInformation

IRP_MJ_SET_INFORMATION有个特殊的参数:AdvanceOnly,DDK中说明如下:

IrpSp->Parameters.SetFile.AdvanceOnly

Specifies conditions for the setting of each information value. If TRUE, each information value should be set only if greater than the current value. If FALSE, each information value should be set only if less than the current value.

实际实现中,此参数只针对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来处理的。

灯下黑-海盐访友

上海至海盐也就一个半小时车程,这么近的距离,但不少同学都已是11年未见了,真是说不过去。倒是申武和海龙自打从海盐跳到海阳后还能隔三岔五地来上海。

想想同在上海的一帮同学也一样,从最早的一年几聚,到现在的几年一聚,而且10多个人都能聚齐已是不可能的了。

这次见到了石头和小胖,曹勇出差了,老董没能联系上。这两天遭遇高温天气,遂取消南北湖散步,午饭过后直接赶往杭州。

P1020451

临走时才仓促拍了张合照,可回到上海发现相机SD卡被我摔松脱了,照片没能保存,但意料之外的是LX5竟然有内置闪存,失而复得!

偶得【二】

上篇blog里说,怎样开始以及从哪里开始比开始更重要,但转念一想,觉得最重要的还是坚持。如果当初坚持把影片《The Time Traveler’s Wife 》看下去,肯定也会觉得好看,毕竟是金子总会发光的。

不得不说,现在网络盗版太方便了,以至于大家都不再珍惜。如果是去电影院,一旦进去以后,很少人会看到一半就出来的。就我来说,就只有一次看到一半就出来的经历。

就像是做事情,不管大小,只有做了才清楚其中难易,无论计划得多详细,总会有想不到的地方,可能开头顺利但过程却曲折,也可能相反,只有真正去做了才知道,之前的计划都只时揣测。

如果想知道一本书精彩不精彩,只有读了才知道;想知道一个故事有没有趣,也只有听了才知晓。