本人目前就职于烽火集成,从事云计算产品架构设计相关工作,长期专注于内核、虚拟化、分布式、云计算等方向。
技术交流请联系:xiaoding@fiberhome.com
xen的热迁移代码使用的是precopy算法,简单描述下算法
使用了3个位图来记录需要迁移的page
to_send:上一次迭代的脏页情况,
to_skip:当前脏页情况。
to_fix:最后停机copy的页
Xen 利用循环迭代的方式将内存页拷贝到目的主机上,在第一轮迭代中,所有的页都被
拷贝,以后每轮迭代只传送上一轮传送过程中被修改过的内存页。
在每轮迭代结束前,调用
影子页表的清空操作(XEN_DOMCTL_SHADOW_OP_CLEAN)一将脏页位图拷贝到 to_send
中,该操作同时清空脏页位图。
在下一轮迭代开始后调用影子页表查看操作
(XEN_DOMCTL_SHADOW_OP_PEEK)将脏页位图拷到 to_skip。并根据 to_send 和 to_skip
判定该页是否作为传送对象。
好了,老规矩直接上代码。
xen的热迁移和save虚拟机调用的是同一个接口,这里和kvm的思路是一样的。save到文件和发送到对端
都是将一段流发送出去。
在tools/libxc/xc_domain_save.c中xc_domain_save函数实现了热迁移的全过程。
由于函数比较大,截关键的地方来说明。
很明显,下面的代码主要调用了xc_shadow_control函数,向xen开启了logdirty形式。
这个xc_shadow_control函数中的具体作用,后面还会详解。也可以看到如果不是live形式,
会直接suspend虚拟机,这样就不会形成脏页了。
然后就是要建立迁移需要的bitmap
接下来会开始进行迭代copy状态
上面讲了迁移的基本算法,那么一些细节就是接下来描述的。
比如是谁来记录脏页的?还有脏页记录到哪里了?
这就不得不提到EPT,EPT是intel在虚拟化下提供内存访问加速的特性,在热迁移时,需要让EPT来帮忙记录脏页。
上面提到了xc_shadow_control函数,这个函数很简单,其实就是将传递的参数进行封装,然后发给xen来进行接下来
的处理。
xen中的arch_do_domctl实现了对这一调用的后半段处理,可以看到迁移使用的系统调用其实是
在paging_domctl函数中
paging_domctl函数中就可以看到刚才在迁移中开启logdirty状态,获取dirty页的相关操作。
xen下面对页的虚拟化采用了两种,一种是影子页表形式,主要在xen/arch/x86/mm/shadow目录下,另一种是EPT形式
,在xen/arch/x86/mm/hap目录下。关于如何开启logdirty状态,等细节请自己翻看代码。这里简述下过程。
p2m表中有标记位为logdirty状态,这里开启时候,就遍历所有的p2m表项,然后设置标记位。在虚拟机运行中,如果
遇到标记了logdirty状态的页就会vmexit到xen中,xen在vmx_vmexit_handler中对异常进行处理,调用
ept_handle_violation函数来处理,经过hvm_hap_nested_page_fault调用paging_mark_dirty函数来对页面进行标记
。
paging_mark_dirty函数就是在页被标记位logdirty时候对页进行的处理。
接下来看看,在接收到XEN_DOMCTL_SHADOW_OP_PEEK或者XEN_DOMCTL_SHADOW_OP_CLEAN后,如何拿到bitmap
到此,xen的迁移介绍完了。