我们都知道KVM支持在线迁移,而其在线迁移是通过内存预拷贝(迭代拷贝)机制来实现的。预拷贝的一个思想就是不断记录脏页并每一轮迭代拷贝脏页面,直至达到一定的条件就退出迭代,进行最后的停机拷贝。关于预拷贝的原理我之前有博客进行了简单分析,在这里就不重复说明了。那这篇文章主要是就其中的脏页记录机制从源码层面进行分析。
这里分析的代码版本是kvm3.10.1和qemu 1.5.3。我们直接进入到迁移(migration)的线程函数Migration.c--->migration_thread(),直接看代码:
static void *migration_thread(void *opaque)
{
//.........//省略部分代码
qemu_savevm_state_begin(s->file, &s->params);
while (s->state == MIG_STATE_ACTIVE) {
int64_t current_time;
uint64_t pending_size;
if (!qemu_file_rate_limit(s->file)) {
DPRINTF("iterate\n");
pending_size = qemu_savevm_state_pending(s->file, max_size);
DPRINTF("pending size %lu max %lu\n", pending_size, max_size);
if (pending_size && pending_size >= max_size) {
qemu_savevm_state_iterate(s->file);
} else {
//..........//省略部分代码
qemu_savevm_state_complete(s->file);
//..........//省略部分代码
}
}
//..........//省略部分代码
}
//..........//省略部分代码
return NULL;
}
这个函数主要是完成迁移的初始化以及内存拷贝过程,这里先看一下里面qemu_savevm_state_begin()这个函数,他里面调用了save_live_setup这个函数指针,这个函数指针在之前被注册,指向了ram_save_setup()这个函数,具体的注册过程这里不进行分析,根据代码追一下可以追到的。ram_save_setup()主要是进行一些初始化的工作,下面看ram_save_setup()这个函数:
static int ram_save_setup(QEMUFile *f, void *opaque)
{
........
migration_bitmap = bitmap_new(ram_pages);
bitmap_set(migration_bitmap, 0, ram_pages);
migration_dirty_pages = ram_pages;
........