Chinaunix首页 | 论坛 | 博客
  • 博客访问: 196744
  • 博文数量: 77
  • 博客积分: 1749
  • 博客等级: 上尉
  • 技术积分: 810
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-28 18:27
文章分类
文章存档

2012年(28)

2011年(49)

分类: 虚拟化

2011-12-15 13:33:50

经过多日的试验,终于找到错误的原因了,原因如下:

在Xen中,HYPERVISOR_multicall的响应函数是do_multicall,在这个函数的最后一行调用了一个hypercall_create_continuation函数,用来resume当前的hypercall。具体做的事情是为Guest OS准备好context(栈及寄存器),然后重新执行INT 82陷入指令。要让虚拟重新执行陷入指令的处理又分为再种情况:假如是PV的虚拟机,把EIP减2,重新执行int 0×82或者syscall指令;假如是HVM,那么不需要对EIP作处理,因为vmcall产生的是fault,指令会重新自动执行。

那么,Xen在什么时候需要创建Continuation呢?常见的代码形式是:

1
2
if ( hypercall_preempt_check() )
    hypercall_create_continuation(...)

hypercall_preempt_check又是干什么的呢?假如当前物理CPU有等待处理的softirq,或者PV中的VCPU中有可投递的upcall(pending且!masked),那么它的返回值就为真。(HVM这里先不讨论)

即是说,Xen在执行某些Hypercall的时候,有可能处于一种不能抢占CPU的状态,所以必须让客户虚拟机重新再执行一次Hypercall。

受影响的Hypercall有:

__HYPERVISOR_hvm_op
__HYPERVISOR_mmuext_op
__HYPERVISOR_mmu_update
__HYPERVISOR_domctl
__HYPERVISOR_set_trap_table
__HYPERVISOR_memory_op
__HYPERVISOR_multicall
__HYPERVISOR_console_io

其他的Hypercall为什么不会有这样的问题呢?那自然是因为其他的Hypercall在执行的时候可以保证当时所处的状态是“干净”的。

reference: http://blog.liuw.name/932


现在回想一下,错误也并不复杂,那么为什么自己竟然花了这么长时间才发现呢?现在把思路整理一下:

当出现错误时,先检查自己的程序是否修改正确。这一步是必须得,正确。

由于错误的外在表现是dom0不能启动,因此我走上了一个错误的道路,希望设置一个flag来标识dom0是否初始化完成,若完成则随机,否则不随机。

首先,这样的想法很肤浅,因为在内核初始化的时候,很多其他的hypercall,都是可以正确执行的,说明改变参数导致的错误并不general,而是针对multicall的,我没有理由怀疑是由于什么东西没初始化好才导致multicall出错。其次,我的随机只是在数值上改变了形参,不会出错的。

但是在设置flag的过程中,我也学习到了很多知识,比如我了解了内核初始化的流程,start_kernel, cpu_idle, init_post, free_mem, 内核保护数据等。我还懂得了设置per cpu data,以及使用它们,这对于我后来看懂源码帮助很大。我还学习到了,内核启动时printk太多东西会导致内核死掉,因为单线程时没有人去唤醒,所以kernel会一直wait。

我甚至还尝试了史上最笨蛋的方法,一个个排查kernel中调用multicall的位置,希望在kernel中找到某个特殊的调用点然后再探究原因,足足有20+个,虽然找到了是某个multicall的问题,但是还是没有找到原因,也不可能找到原因!因为这根本就不可能是问题。

虽然设置启动时的flags可以保证dom0启动,但这只是个巧合,虽然排查multicall也可以启动dom0,但那也只是巧合!


正确的思路是,我只修改了形参,kernel里100%是不会有问题的,entry.S中处理int82请求的汇编,那里应该仔细看一下,其实那里就提到了continuation,只不过我不懂,就忽略了,结果忽略的地方就是出问题的地方。然后是Xen里,我以为一进入do_multicall就还原参数,后面使用到的都是还原过后的参数是100%没问题的,但是没有想到的是,同一个multicall很有可能又被送入do_multicall再执行一遍!!!

所以说,效率低,一是因为自己只是储备不够,看到continuation不能立刻反应到“计算过程的重构”,二是看源码不认真,一知半解,其实之前也看到过hypercall_create_continuation的函数体,但只是一带而过,与其这样急躁,还不如静下心来,真正把代码的细节读懂。


PS:hypercall_create_continuation里还有传入个数不确定参数,并使用这些参数的处理方法,值得好好学习。“hi”

阅读(2351) | 评论(7) | 转发(0) |
给主人留下些什么吧!~~

wang_nets2012-05-09 21:08:10

anitawang1989: 酱紫,总之问题解决了就恭喜了~~~.....
嘿嘿,还希望有机会以后多交流一下,可以留个邮箱或者别的什么联系方式么?

wang_nets2012-05-09 21:08:07

anitawang1989: 酱紫,总之问题解决了就恭喜了~~~.....
嘿嘿,还希望有机会以后多交流一下,可以留个邮箱或者别的什么联系方式么?

anitawang19892012-05-09 20:13:42

wang_nets: 这点我也纳闷,不过貌似可以用,串口调试过程中可以看到,会输出大量printk信息,导致系统启动十分缓慢,个人一种dom0假死的假象.....
酱紫,总之问题解决了就恭喜了~~~

wang_nets2012-05-09 14:50:12

anitawang1989: 是不能用printk的,因为xen启动的时候,kernel还没有启动.....
这点我也纳闷,不过貌似可以用,串口调试过程中可以看到,会输出大量printk信息,导致系统启动十分缓慢,个人一种dom0假死的假象

anitawang19892012-05-08 14:30:30

wang_nets: 你好,我最近也在学习Xen,请问你试过在hypercalll中添加printk么?我尝试在do_set_trap_table中添加一个printk,其他地方并未有改动,但是Dom0就启动不了了,请.....
是不能用printk的,因为xen启动的时候,kernel还没有启动。