慎用MmSetAddressRangeModified

MmSetAddressRangeModified用来设置PFN为dirty/modified,并将PTE的dirty位清除。但除此之外,还有个不明显的副作用,看下面的分析:

1: kd> !pte 0xfffff880`0c9e6000
                                 VA fffff8800c9e6000
PXE @ FFFFF6FB7DBEDF88     PPE at FFFFF6FB7DBF1000    PDE at FFFFF6FB7E200320    PTE at FFFFF6FC40064F30
contains 000000003FE84863  contains 000000003FE83863  contains 0000000014516863  contains 000000000FAD7963
pfn 3fe84      ---DA--KWEV  pfn 3fe83      ---DA--KWEV  pfn 14516      ---DA--KWEV  pfn fad7       -G-DA--KWEV

PTE entry 状态为dirty,并且是可写的(writable)。 再看调用MmSetAddressRangeModified后的状态:

1: kd> !pte 0xfffff880`0c9e6000
                                 VA fffff8800c9e6000
PXE @ FFFFF6FB7DBEDF88     PPE at FFFFF6FB7DBF1000    PDE at FFFFF6FB7E200320    PTE at FFFFF6FC40064F30
contains 000000003FE84863  contains 000000003FE83863  contains 0000000014516863  contains 000000000FAD7921
pfn 3fe84      ---DA--KWEV  pfn 3fe83      ---DA--KWEV  pfn 14516      ---DA--KWEV  pfn fad7       -G--A--KREV

PTE entry的dirty位已被清除,但是此pte已被设成了readonly状态了。所以如果再有写操作,必然会导致page fault发生。

这就是我曾遇到的一个Ext2Fsd的bug:Ext2Fsd为了将page cache锁定,创建了MDL并重新映射到系统空间(调用MmMapLockedPagesSpecifyCache)。新映射的va具有dirty及writable属性,故此va在spinlock (DISPATCH_LEVEL)下进行写操作不会导致任何异常。但在提交改动过程中,Ext2Fsd调用了MmSetAddressRangeModified,调用后MmSetAddressRangeModified会将此pte设置为readonly,如果下一次的写操作正好在spinlock下(DISPATCH_LEVEL),将会导致BSOD: DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1),如果在获取spinlock前曾执行过写操作(IRQL < DISPATCH_LEVEL),则会正常触发page fault,然后MmAccessFault会重置pte为writeable,并设置dirty位,此后如果再进入DISPATCH_LEVEL,对此va进行写操作便不会触发page fault了。这就构成了一定的随机性和隐蔽性,给调试带来了很大的麻烦。

明白了问题所在,不妨再做个实验:如果手工将此pte设为writeable的,再进行写操作,cpu应该直接置pte为dirty,而不必调用OS(即page fault)。

对va 0xfffffa60`04ae7000 调用MmSetAddressRangeModified后,

1: kd> !pte 0xfffffa60`04ae7000
                                 VA fffffa6004ae7000
PXE @ FFFFF6FB7DBEDFA0     PPE at FFFFF6FB7DBF4C00    PDE at FFFFF6FB7E980128    PTE at FFFFF6FD30025738
contains 000000007FFC4863  contains 000000007FFC3863  contains 00000000539A2863  contains 00000000149AD921
pfn 7ffc4      ---DA--KWEV  pfn 7ffc3      ---DA--KWEV  pfn 539a2      ---DA--KWEV  pfn 149ad      -G--A—KREV

手工修改 0xfffffa60`04ae7000为writeable,不必置dirty标志:
1: kd> dq FFFFF6FD30025738 l1
fffff6fd`30025738  00000000`149ad921

1: kd> eb FFFFF6FD30025738 23
1: kd> !pte 0xfffffa60`04ae7000
                                 VA fffffa6004ae7000
PXE @ FFFFF6FB7DBEDFA0     PPE at FFFFF6FB7DBF4C00    PDE at FFFFF6FB7E980128    PTE at FFFFF6FD30025738
contains 000000007FFC4863  contains 000000007FFC3863  contains 00000000539A2863  contains 00000000149AD923
pfn 7ffc4      ---DA--KWEV  pfn 7ffc3      ---DA--KWEV  pfn 539a2      ---DA--KWEV  pfn 149ad      -G--A--KWEV

在进行写操作前可以对KiPageFault或MmAccessFault设置断点,然后进行实验。看断点会不会触发,操作后再检查一下pte的dirty标志是不是已经设置了。具体实验结果,就留给读者自己去验证了。

在DISPATCH_LEVEL中操作paged va无论是已将其page锁定还是重新映射过,都有点如履薄冰的感觉,特别是对file cache,Cache Manager的不少内部操作都会更改pte的属性或调用MmSetAddressRangeModified,到处都可能有陷阱。所以最保险的方式还是不用spinlock 微笑

翻墙

“翻墙”也该该算是中国特色之一了,差不多所有中国互联网用户都曾尝试过。原因很简单,就起因于“Wall”的存在,而且还是个“The Great Firewall”。

墙里没有秋千,墙里也没有佳人,墙里只是个超大的局域网,但相对于世界来说,又是个小圈子。我们所有国人都被限制在一个小圈子里。对全世界开放的所有资源中,只能访问一小部分。好比,当外国人在大舞台上表演的时候,我们只能在小屋里唱KTV,而且还不能随便点歌。

这就是这个国家所造就的最大不公平。这个不公平的后果就是我们在起跑线上就输给了我们的竞争者,我们所看到的世界始终是残缺的,而我们总会慢半拍才能看到最新的资讯。虽然他们有YouTube,我们有Youku,他们有google,我们有baidu,但Youku能替代YouTube,baidu能替代google吗?当你的外国朋友们都在忙着交换facebook链接的时候,你却像个外星人似的一脸茫然,因为你从来没听说过,也不知道它是个什么玩意。这并不是你孤陋寡闻,而是www.facebook.com被墙在外面了,而且我们主流媒体也在刻意过滤着所有的信息。

所以我们翻墙,而且不得不为之!

最早的翻墙主要依赖于国外代理服务器,很多网站都会定期发布一个代理服务器列表。很有耐心地我们不得不一个一个地去尝试,总能找到个好用的。那个时候我在用httpport。

现在大家都开始用VPN了,ssh tunnel也是个不错的办法。我两者都在用。下载大文件时我一般选择VPN。但一连VPN,所有网络访问都要走VPN了,连国内网站还要走个大圈,所以很多时候Firefox+foxyproxy+myentunnel方式,更省事快捷。

有时也用ssh tunnel方式,但仅限于指定网站和端口的服务。如公司VPN会封掉smtp端口,用这种方式可以将本地端口转到smtp server 上。

其实还有种方式我用得也相当多,就是通过https://www.ggssl.com看网页面快照。

Windows Boot Manager 语言设置

Windows Boot Manager显示中文有些夸张,特别是中英文混合使用的时候,中文菜单项总是显得很长很长。

其实改成英文的很方便:

bcdedit /set {bootmgr} locale “en-US”

当然还要改所有含有中文的菜单项,不妨给它们起个英文名,如将”较早版本的Windows”改成“Windows XP”:

bcdedit /set {ntldr} description “Windows XP”

后Oracle生活

离开Oracle有几天了,但并没有闲下来,一直在忙Ext2Fsd hash-tree directory indexing的实现。代码工作已基本完成,简单的测试只在laptop里的虚拟机里做过,但后面的测试才是真正让人皱眉的事情。

从xp到vista再到win7,无论32位还是64位,所有系统上都要做个测试才行。我所有的虚拟机都跑在Dell T7500工作站上,但工作站已于上周二还给公司了,所以还要将所用数据迁移到另外一个系统上来。这个周末差不多全耗在这个上面了。当初打算好的目标机器出现了个新问题,主板一通电就自动开机,关机时系统只会重启。电源问题好像是ASUS的诟病,遇到这个问题的人还真不少。这是个AMD双核系统,主板是很老的M2N4-SLI,内存已升至8G,跑几个虚拟机还是没问题的。一直纠结在换个烧包的  i7或6核的AMD还是买个新主板接着装老酒的选择上,但最后还是决定买MSI的KA790GX-M替换老的M2N4主板,旧U及老DDR2接着用。几番折腾,搞定系统。又重新接好AVR m8 (我的电源控制系统),这样可以远程控制电源了。顺代将我的小P3 Server的系统盘换了,原来的是有坏道的40G 2.5寸盘,还是03年买的呢,用到现在还挺好,但空间不够了。现在换成了120G的。Linux的resize2fs真好使,为什么Windows总要依赖于第三方的支持?!

系统搭好了,测试机也有了,但下面的问题更让人头疼,怎么设计测试及怎么来测!想得我头都大了,也没有想好。或许这是惰性想推迟行动的绝佳借口,呵呵。