设为首页 收藏本站
查看: 1201|回复: 0

[经验分享] qemu-kvm虚拟机live迁移源代码解读

[复制链接]

尚未签到

发表于 2015-10-10 09:06:34 | 显示全部楼层 |阅读模式
首先,使用kvm正常打开一个虚拟机:sudokvm ./xp1.qcow2
然后,再使用kvm命令打开同一个虚拟机。使用如下命令:sudokvm ./xp1.qcow2 -incoming tcp:0.0.0.0:11111
读者可能会说,两台虚拟机同时使用同一个image,会造成image数据的丢失,可能会彻底破坏整个虚拟硬盘的数据完整性,从而造成数据丢失,甚至操作系统都无法启动!
是的,但这里的-incoming选项,实际上并没有真正启动虚拟机。它首先创建TCP等链接,准备接受虚拟机迁移的数据传入,然后就暂停了虚拟机的执行。直到虚拟机迁移完成后,才会恢复进入虚拟机运行状态。因此,它在迁移完成前,并没有操作虚拟磁盘,因此不会造成如上的问题。


qemu-kvm:versoin= 1.2.0


源端:
migrate命令会调用hmp_migrate()函数{definedin hmp.c}


hmp_migrate()会调用qmp_migrate(...)函数{definedmigrate.c}
(1) 判断当前migrate状态是否为active;此时迁移状态应该为MIG_STATE_SETUP
(2) 判断是否有blockmigrate设备存在;
(3) 初始化;
      调用migrate_init(&params)
(4) 判断migrate协议:TCP/UNIX/EXEC/FD 开始迁移。
       调用 tcp_start_outgoing_migration(s,p, errp) {p:=host_port}
          exec_start_outgoing_migration(s,p)
          unix_start_outgoing_migration(s,p)
          fd_start_outgoing_migration(s,p)
在这里,假设用的是tcp协议。


tcp_start_outgoing_migration(s,p, errp){defined in migration-tcp.c}
(1) MigrationState中的函数指针赋值
(2) 调用inet_connect(...)连接监听目的虚拟机
(3) 创建迁移处理线程
      调用migrate_fd_connect(MigrationState*s


migrate_fd_connect(MigrationState*s{definedin migration.c 真正的迁移方法}
(1) 当前迁移状态设为MIG_STATE_ACTIVE
(2) 定制QEMUFile文件
    调用qemu_fopen_ops_buffered(...)返回QEMUFile
        1) QEMUFileBuffered初始化
        2) 定制QEMUFile文件
              调用qemu_fopen_ops(...)返回QEMUFile
(3) 调用qemu_savevm_state_begin(QEMUFile,const MigrationParams)
        初始化 se->ops->save_live_setup block_save_setupram_save_setup)
(4) 调用migrate_fd_put_ready(MigrationState*)
    遍历实现设备内存状态保存



migrate_fd_put_ready(MigrationState*)
(1) 迭代预拷贝IterativePre-Copy{definedin the file savevm.c}
调用qemu_savevm_state_iterate(QEMUFile*)
        1)遍历实现设备内存状态保存
            调用se->ops->save_live_iterate(f,se->opaque){等于block_save_iterateram_save_iterate}
(2) 唤醒虚拟机状态
    调用等于qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER)
(3) 调用vm_stop_force_state(RUN_STATE_FINISH_MIGRATE)
    1) 终止虚拟机的运行
        调用vm_stop(RUN_STATE_FINISH_MIGRATE)
(4) 停机拷贝,保存新的数据{definedin the file savevm.c}
调用qemu_savevm_state_complete(QEMUFile*)

  • 调用se->ops->save_live_complete(f,se->opaque){save_live_complete = block_save_completeraw_save_complete}
  • 调用vmstate_save(…)完成停机拷贝
(5) 迁移完成,提交信息{definedin migration.c}
    调用migrate_fd_completed(MigrationStateb*)
        1) 迁移完成,释放资源
                migrate_fd_cleanup(MigrationState*)
        2) 释放资源成功,设置迁移状态:=MIG_STATE_COMPLETED
                s->state= MIG_STATE_COMPLETED;
        3) 否则,s->state= MIG_STATE_ERROR
(6) 判定迁移状态是否完成,s->state== MIG_STATE_COMPLETED or not。完成,则迁移结束;否则,重新运行源VM



目的端:
调用main(...){defined in vl.c}
(1) 解析命令行参数,初始化等
(2) 判断是否有待迁移虚拟机
    调用qemu_start_incoming_migration(incoming,&errp)
        1) 选择KVM支持的迁移通道
            调用 tcp_start_incoming_migration(p,errp)
                exec_start_incoming_migration(p)
                unix_start_incoming_migration(p)
                fd_start_incoming_migration(p)


tcp_start_incoming_migration(constchar *host_port, Error **errp) {defined in migration-tcp.c}
(1) 打开监听
    调用inet_listen(...)
(2) 调用qemu_set_fd_handler2(...)
    注册IO事件,加入到io_handlers链表中,并将IO事件的函数指针初始化,尤其是ioh->fd_read= fd_read = tcp_accept_incoming_migration




tcp_accept_incoming_migration(void *opaque) {defined in migration-tcp.c}
(1) 接受连接
    调用qemu_accept(...)
    调用accept(...)
(2) 接受迁移,打开套接子
    调用qemu_fopen_socket(int){defined savevm.c}
    通过调用qemu_fopen_ops(s,NULL, socket_get_buffer, socket_close, NULL, NULL, NULL)注册文件套接字QEMUFileSocket
(3) 进程接受迁移
    调用process_incoming_migration(QEMUFile*)
(4) 迁移结束相关操作


process_incoming_migration(QEMUFile*) {defined in migration.c}
(1) 导入状态,从套接字中获取VM状态
    调用qemu_loadvm_state(f)
        se->ops->load_state()
(2)qemu_announce_self ()
(3)bdrv_clear_incoming_migration_all ();
(4)bdrv_invalidate_cache_all ()
(5) 如果成功:vm_start();若失败,停止runstate_set()


qemu_loadvm_state(QEMUFile*f){ defined in savevm.c}
(1) 声明loadvm_handlers链表,并初始化,注册LoadStateEntry*le
(2) 判断是否有迁移,没有则return-EINVAL;否则,继续
(3) 循环,获取(loadsavevmsection 标识,
(4) 如果是扇区开始:
    获取(loadsection_idinstance_idversion_id
    LoadStateEntry*le分配空间,并赋值其成员,将当前le插入loadvm_handlers链表
    并加载savevm状态
        调用vmstate_load(f,le->se, le->version_id)
    回到(3)
(5) 如果是扇区结束标识:
    获取(loadsection_id,遍历loadvm_handlers,寻找扇区section_id
    并加载savevm状态
        调用vmstate_load(f,le->se, le->version_id)
    回到(4)
(6) 同步所有cpu,初始化
(7) 注销loadvm_handlers,释放LoadStateEntry*le
(8) 成功返回0,失败返回<0


注意:所有支持虚拟机活迁移的虚拟设备,都需要调用register_savevm_live方法,提供保存状态的SaveVMHandlers*save_live_iterate函数,供活迁移开始时被调用。正是因为块设备注册了SaveStateEntry对象,才使KVM能够支持image不共享的活迁移。
块设备live迁移初始化:
    调用blk_mig_init(void)
参考:   http://www.cnblogs.com/armlinux/archive/2011/05/10/2390904.html
            http://blog.iyunv.com/chenglinhust/article/details/8808731
            http://blog.iyunv.com/chenglinhust/article/details/8703131

迭代预拷贝:http://yang19890314.blog.iyunv.com/1620466/1163624

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-124928-1-1.html 上篇帖子: virtio一个KVM虚拟环境下针对I/O虚拟化通用框架 下篇帖子: kvm虚拟机扩展磁盘空间
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表