测试ali-kernel中发现,如果进程正在对一个ext4文件系统做普通的写入:

dd if=/dev/zero of=/test/ok bs=1M count=1048576

突然拔掉盘,由于io-error-guard的作用,能迅速把ext4变为read-only,dd进程直接返回Input/Output error然后退出,但是如果接着umount,那么umount命令就一直hang住了。
跟了一下发现是文件系统发现io错误开始清除inode,ext4_destroy_inode() --> ext4_ioend_wait()判断i_ioend_count总是不为0,所以一直等待。没啥新鲜的,加trace跟踪i_ioend_count,原来ext4_free_io_end是负责将此计数减一的,但是调用ext4_free_io_end的有很多函数,看上去ext4_end_io_buffer_write()应该是调用者(名字叫buffer_write嘛,普通的写入就是这个),查了半天,这个函数根本不调用ext4_free_io_end(),那谁在调,又查,才发现是ext4_end_Io_buffer_write()在结尾时调用

queue_work(wq, &io_end->work);

让工作队列来负责下面的事(这个work_queue,最容易看漏了),实际的工作交给ext4_end_aio_dio_work()来做了,你看这函数名字,又是aio又是dio的,我的写入既不用aio也不用dio,却非得走到它这里来,太误导了,还是upstream的名字改得对,就叫ext4_end_io_work()得了。然后就一眼看出ext4_end_aio_dio_work()里有蹊跷了,里面有个逻辑,如果io出现错误无法进行,居然不调用ext4_free_io_end而直接返回了,那肯定会造成计数无法变为0,ext4_ioend_wait当然就总等着了。
再看upstream,唉,很遗憾,已经被Jan Kara修复了,patch在这里

还要感谢鸿蒙(邹巍)同学对我的大力支持,千里迢迢寄过来了Sandybridge服务器,一机在手,调试不愁。能亲手插拔硬盘,才能发现这样的问题,以后才能多多方便大家。