台湾环岛骑行路线小结

总里程: 1196KM

D1/0720:  103KM 晴,东南风,南行微顶

站点:台北-八里-大圆-观音-南寮
路线:台北内湖区-民权东路-台北大桥-环堤大导-台15-台61-台15

D2/0721: 186KM 晴转雨,东南风,南行顶风

站点:南寮-竹南-通霄-苑里-大甲-台中港-梧棲-鹿港-麦寮-台西-口湖 186KM
路线:台15-台61-台1-台17

D3/0722:85KM (台南休整)  阴,间歇小雨

站点:口湖-东石-布袋-北门-七股-台南
路线:台17-182-台南一中

D4/0723:174KM 晴转雨,东风

站点:台南-永安-高雄-东港-枋寮-车城-垦丁(水泉) 
路线:台南一中-182-台17-台1-台26-埔墘路

D5/0724:162KM 阴,小雨不断

站点:垦丁-台湾最南点-满州-旭海-寿卡-大武-知本
路线:
顶泉路-下泉路-台26-200甲-200-199甲-199-台9

D6/0725:167KM 阴,小雨不断,中午开始暴雨

站点:知本-台东-成功-长滨-丰滨-水琏-12号桥
路线:
台9

D7/0726 157KM 多云

站点:12号桥-花莲-南澳-东澳-苏澳-头城
线:台9-台2

D8/0727 160KM 晴,气温相当高

站点:头城-北关-大里-福隆-基隆-金山-最北点-淡水-台北
路线:台2-台2乙-民权东路

骑行环岛,出发了!

D0 7/20 台北-南辽          96 km  上午搞定车子,下午开始
D1 7/21 南辽-后龙-鹿港    133 km
D2 7/22 鹿港鎮-台南       130 km
D3 7/23 台南-高雄-枋山    160 km
D4 7/24 枋山-垦丁-滿州     80 km  垦丁看海,游泳
D5 7/25 滿州-大武-台東    130 km
D6 7/26 台東-成功-豐濱    120 km
D7 7/27 豐濱-花蓮縣       120 km
D8 7/28 花莲-礁溪         140 km
D9 7/29 礁溪-淡水-台北    160 km

Intel并购Whamcloud

Whamcloud并购一事,网上已是消息满天飞,但不是圈内人士未必关注。我现在虽已跳出圈外,但还是有着“切身利益”的。

下月准备去北京出趟差,打算多呆几天,要让北京的几个老同事轮流请客才行。这通并购,也同样会让他们发笔不大不小的财,哈哈。我就是担心,好不容易才减下去的几斤肉,在这一通胡吃海喝之后,会不会加倍地又给我长回来?!

此次并购估计是CFS/Lustre的最后一并了,从前到后,共4次了,看下图:

CFS -----> SUN -----> Oracle

          |                 |

          |                 +----> Whamcloud -----> Intel

          +----- > ClusterStor –> Xyratex

夏日事多

这几天过得太匆忙,也许是把星期一给过丢了,以至一度认为今天是周二,直到朋友打电话来问明天要不要去攀岩时才注意到今天已是周三了。

这个平平常常的不二小三的日子里,我过得也是普普通通,象往常一样被各种小事、大事、或身边事挤得满满的:

1)从早上直到下午,一直在调程序,搞定一个“六亲乱认”的问题,是由于打开文件时对一个标志位的处理缺失导致的。

2)午饭时间下起了暴雨,阵雨来得凶,走得也快。待雨停,又去了趟面包店。

3)下午正和朋友讨论问题的当空,QQ上便传来严冬冬山难的消息。将自己托付与山,是职业登山者的宿命。只是生命如此年轻,正值年少轻狂,誓言征服全天下的壮志心胸!

4)“REPUBLIC OF CHINA”的通行证终于出来了,当个中国人真不容易,特别是再加个“THE PEOPLE’S” 前辍的情况下。

5)晚上跑步,天热,只跑了5k,一边跑一边筹划着马拉松的事情,事实是等我跑完,马拉着松早没影了。加量的问题真是个问题,也是个相当“科学”的问题,也是个决心  vs 惰性的问题。

7)就在跑步前,想给平板里拷几部电影,用了一个taobao上购物卖家赠送的读卡器,不太灵光,32G的TF卡读不出来了。跑完步,草草冲了一个澡,便开始尝试数据恢复。FAT32格式太不靠谱,动不动就会受伤。分析下来,损坏相当严重:

a) Boot Record被写坏了,好在这个可以重建 b) FAT Table 1和FAT Table 2的第一个扇区也全写坏了。Root Directory在第一簇,即2号簇,分析下来第一扇区后面的数据是连续的,同属一个文件(第二个扇区房始值是0x81,一簇大小是16K,即0x4000),所以第一扇区的重建比较轻松。 c) 电影目录的首簇号失效,文件名查找找到的位置竟然是0x701400200,不能被簇整除。将内容移到0x701400000,并修改电影目录的首簇号为0x001C0002。

经过以上修改,系统还是不能正常挂载,但好在winimage可以读取,最重要的数据(安装程序、ROM的备份)都可以备份出来了,电影文件部分可以正常读取,后来就没在花时间搞,只要将程序及ROM的备份搞定就完全没压力了。

8)等折腾完,睡觉时已是00:20,不平静的“小三”终于过去了。

<此日志为周四记录周三的事,主要是想再看一眼“小三”,渴望同“小三”一起多走一天>

关于工程师的笑话

调侃工程师的笑话,多为工程师自娱自乐所为,其中逻辑及笑点也是非工程师所能深解,但好在工程师也不是什么高深的职业。

话说,某工刚下班,家里领导打来电话说:路上买三个馒头,看到西瓜买一个。结果等此工回到家时,领导看到他只买了一个馒头,并不是三个!

讲到此处,工程师们应该已笑开了怀。这则笑话以前就曾看过,后来,与朋友自驾浙江游玩时,一朋友又讲起此笑话,严格意义上当时只我一个算是个“工程师”,但这年头,是个知识分子,哪有没写过程序的?!所以全车人笑地还是异常热烈,特别是再经过“非工程师”人的诠释,以至这个如此简单的笑话几乎让我们笑了一路子。

还有个笑话:作家、物理学教授、和工程师开会回来,驾车驶进盘山小路,结果刹车失灵,车辆直冲而下,所幸为小树所阻,三人才得以死里逃生。从惊吓中恢复过来后,作家先发话说来灵感了,要将此次经历写成一部超惊险超刺激超恐怖的超现实体验主义小说;物理学教授也跟随,一定要搞出个数学模型来描述此次刹车片摩擦受热失灵的量子状态以及车辆带动力俯冲下山的动量矢能转换,话虽未说完但早已是一脸的急切;此时的工程师却是眉头紧缩,满脸疑惑地摇着头说:咱们为什么不再重现一次好找出问题的根本原因?

离奇事件薄之Irp死亡未遂

白天在外面耗了一整天,和各色朋友们讨论了一整天的新公司初创、经营、账务、税收等相关的问题,竟也蛮有兴致,也费了相当的口水,等回到家时间已很晚了,可精神却还是异常兴奋,只得爬起来找点事打发一下过剩的精力,第一直觉上便想到了前阵子曾遇到的一个稍许离奇的问题。

内容上可接承以前的一篇日志《离奇死亡事件薄之CoCreate篇》,于是继续取题《离奇事件薄》。细节如下:

驱动程序中要转向IRP_MJ_DIRECTORY_CONTROL/IRP_MN_QUERY_DIRECTORY,即Directory Enumeration操作,以方便处理此目录下所有的文件项。

由于会涉及文件I/O操作,不得不将操作移至系统线程中来做(至于为什么,请读者自己思考),所以在用户请求线程中不得不将原Irp请求的完成延后(pending),函数原型可简化成如下二个函数:

/* 用户线程环境:直接处理 IRP_MJ_DIR_CTRL / IRP_MN_QUERY_DIRECTORY */

NTSTATUS MyQueryDirectory(DevObj, Irp)

{

        ……
        MyQueueToSystemThread(DevObj, Irp);
        return STATUS_PENDING:

}

/* 系统线程,用以处理面向新路径(Dcb)的IRP_MN_QUEYR_DIRECTORY操作 */

NTSTATUS MySystemThreadHandler(DevObj, Irp)

{
        PIRP newIrp = IoAllocateIrp(newDevObj);
        ……
        IoCallDriver(newDevObj, newIrp);
        KeWaitForSingleObject(…):

        /* 处理返回的目录项 */
        ……
        /* 完成原用户的IRP请求 */
       IoCompleteRequest(irp, IO_NO_INCREMENT);

}

代码在逻辑上并没有问题,MySystemThreadHandler()正确获取目录项内容并实施对目标项的逐一检查,之后再完成用户所发的Irp请求,Irp的状态被系统(I/O Manager)修改为完成状态,此过程中并没有异常。但最早发出IRP_MJ_DIR_CTRL / IRP_MN_QUERY_DIRECTORY请求的用户线程却被永远地挂起来了,原Irp内容依然有效,虽然其状态已被标记为“完成”。

调试发现,由于系统线程优先级稍高,MySystemThreadHandler()完成Irp的操作竟然先于MyQueryDirectory()返回至I/O Manager。

执行顺序如下:
时间1:MyQueryDirectory() 添加一个新任务至系统线程队列
时间2:MyQueryDirectory() 被系统挂起了
时间3:系统线程执行MySystemThreadHandler()来处理时刻时间1所添加的任务
时间4:MySystemThreadHandler()执行完毕
时间5:原用户线程MyQueryDirectory()被唤醒,并返回STATUS_PENDING给I/O Manager

看到此序列,对于熟悉Irp操作规则的开发者来说,问题已经明了:显然是对此Irp的第二阶段用户线程环境相关的处理没有进行(Stage 2),也就是说,添加Kernel Apc的部分被跳过了。

一般Irp的完成要经过两个过程(可参见本文末所附文档链接):
Stage 1: IofCompleteRequest(): 完成与请求线程环境无关的操作
Stage 2: IopCompleteRequest(): 与Kernel Apc中执行,用以完成与请求线程相关的操作

之所以Stage 2的IopCompleteRequest会被跳过,有两方面的原因:

  1. Windows内核在处理IRP_MJ_DIR_CTRL/IRP_MN_QUERY_DIRECTORY请求时会默认加上标志位IRP_DEFER_IO_COMPLETION。据我所知,仅对DeviceIoControl操作不加此标志。当此标志位被设置的同时,如果Irp的Pending位没有设置,IoCompleteRequest()(此函数会调用IofCompleteRequest())则会直接返回,从面不在继续处理第二阶段(stage 2)。
  2. 原用户线程IoCallDriver()返回之后,由于返回值为STATUS_PENDING,I/O Manager将不在调用IopCompleteRequest()

所以二者同时跳过Stage 2,导致Irp的Stage 2处理不会再有机会执行,从而原用户线程也得不到被唤醒的机会了。

解决办法却是异常简单,在MyQueryDirectory()调用IoCallDriver()之前,或MySystemThreadHandler()调用IoCompleteRequest()之前将Irp设为PendingReturened非状态即可,此操作由系统支持函数IoMarkIrpPending()来做的。

最后,不妨再复习一下OSR介绍Irp操作的经典之作吧:《Secrets of the Universe Revealed! - How NT Handles I/O Completion