最新消息:

Sheepdog块设备驱动死锁的问题

未分类 admin 3458浏览 0评论

sheepdog的块设备驱动写好有一段时间了,陆续修改了几个版本之后,近期进行压测的时候遇到一个死锁的问题,头痛了一个多星期,今天请教了一下淘宝内核组的@伯瑜同学,在他的热情帮助下分析出来了死锁出现的原因,解决的办法暂未找到,或者说这问题无解,待我细细说来。

问题是这样的,在把Sheepdog中的某个VDI挂载成块设备之后(/dev/sheepa),我在sheepa上安装了一个debian,然后启动QEMU,启动盘就设为/dev/sheepa:

qemu-system-x86_64 -m 512 -hda /dev/sheepa

启动完成后开始狂做IO,也没用啥复杂的办法,就是dd

dd if=/dev/zero of=xxx bs=4096 count=1000000

就这样在写入几个G的数据后就有可能会出现死锁,而且出现的机率很低,复现一次要花好长时间,有时候几十个G的磁盘都被Sheepdog写满了也复现不出来。死锁发生时,sheep其中一个进程会D住(一个sheep会启动两个进程,一个是主进程,一个是日志进程),这时候QEMU也会hang住,甚至在有些极端的情况下ps -ef也会hang住。

我在sheep block driver里面加入debug信息定位到hang住的位置,是在read_reply()这个函数里面,这个函数是在等待sheep的请求响应,这个时候sheep已经hang住当然不会响应,于是QEMU的IO一直没有返回,也会一直hang在那里,可为什么sheep会hang住呢,这个问题是当时我没想明白的,后来经过伯瑜大神的指点才明白过来。

用sysrq-trigger查看各进程的状态,sysrq-trigger是个好东西,调试内核相关的代码还是不能少了这些工具的帮助,文档在这里http://kernel.org/doc/Documentation/sysrq.txt

echo t > /proc/sysrq-trigger

echo t的作用就是把当前所有进程和状态都打到/var/log/messages里面去,看一下D住的两个进程sheep和QEMU的状态:

[10388.111972] sheep D ffff88011e213580 0 2522 1 0×00000080
[10388.111977] ffff8800cc8736b8 0000000000000086 ffff88010476ae40 ffff8800cc873fd8
[10388.111982] ffff8800cc873fd8 ffff8800cc873fd8 ffffffff81a0d020 ffff88010476ae40
[10388.111987] ffff8800cc873688 ffff88010476ae40 ffff88011e213e48 0000000000000002
[10388.111992] Call Trace:
[10388.111997] [] ? __lock_page+0×70/0×70
[10388.112000] [] schedule+0x3f/0×60
[10388.112004] [] io_schedule+0x8f/0xd0
[10388.112009] [] sleep_on_page+0xe/0×20
[10388.112015] [] __wait_on_bit+0×60/0×90
[10388.112019] [] wait_on_page_bit+0×80/0×90
[10388.112024] [] ? autoremove_wake_function+0×50/0×50
[10388.112030] [] shrink_page_list+0x20e/0×960

[10388.113765] qemu-system-x86 D ffff88011e213580 0 11870 3433 0×00000080
[10388.113770] ffff88001e005b98 0000000000000086 ffff880083b71720 ffff88001e005fd8
[10388.113775] ffff88001e005fd8 ffff88001e005fd8 ffffffff81a0d020 ffff880083b71720
[10388.113780] 0000000e1e005ba8 ffff880083b71720 ffff88011e213e48 0000000000000002
[10388.113785] Call Trace:
[10388.113790] [] ? __lock_page+0×70/0×70
[10388.113794] [] schedule+0x3f/0×60
[10388.113797] [] io_schedule+0x8f/0xd0
[10388.113802] [] sleep_on_page+0xe/0×20

贴了其中一部分相关信息,D住的sheep进程正在shrink_page_list,说明sheep在申请内存的时候空闲内存不够了,sheep需要回收一些内存,这时候kernel发现某一个内存页可以回收,于是尝试回收该内存页,在该页回收完成并可用之前sheep会hang住等待该内存页的回收。

而QEMU也是D在了某内存页的处理上,而死锁的产生是由于sheep在等待回收的那个内存页由QEMU持有,QEMU要释放这个页面就需要将page cache回写,而QEMU的backend存储用的是sheepdog,所以QEMU持有的那个内存页在回写到磁盘的时候会发请求给sheep块设备driver,driver在收到请求后把请求再扔给sheep,只有在sheep返回后这个请求才算处理成功,也就是这个要释放的内存页才算成功回写至磁盘,而这时的sheep进程恰恰在等待这个内存页,不会响应任务请求,因此就这样死锁了,sheep等待QEMU回写释放内存,QEMU回写需要等待sheep的请求响应,两人谁也不让谁就锁在那里了。

我的host内存相对较大,有4个G,所以这个问题不容易复现,需要大量地写入数据才有可能出现这种竞争场景,如果内存小一些问题出现的机率会更高一些。

这个问题不是编码上的bug,在这种场景下很难避免,解决的办法是sheep block device driver和sheep instance不要在同一台host上,我对这个module的期望也并不是像目前Sheepdog+QEMU一样使Sheep和QEMU运行在同一台host主机上,而是我们的任何一台的客户端机器都可以挂载远端集群上的大块存储空间虚拟成一个大硬盘。因此解决的办法就只能让driver和sheep分开。

这个问题困扰了我好久,分析自己的代码也分析了好长时间,但始终没能自己找出问题所在,还是缺少一种大局观,也缺少一些调试内核的经验,这次经过大神的指点也学会了不少东西,还是值得庆祝的。

FROM:http://basiccoder.com/sheepdog-block-device-driver-deadlock.html

转载请注明:爱开源 » Sheepdog块设备驱动死锁的问题

您必须 登录 才能发表评论!