* [Qemu-devel] [RFC PATCH 0/2] live backup vm @ 2012-12-08 8:24 Wenchao Xia 2012-12-07 10:12 ` Dietmar Maurer ` (2 more replies) 0 siblings, 3 replies; 15+ messages in thread From: Wenchao Xia @ 2012-12-08 8:24 UTC (permalink / raw) To: qemu-devel Cc: kwolf, aliguori, stefanha, Wenchao Xia, blauwirbel, pbonzini, dietmar This patch is a scratch which enables a full live backup of VM, actually it is equal to savevm lively. As a test it uses hmp command migrate to trigger the action. The ultimate goal is providing another command to user as: snapshotvm [with_state] [internal] [live] which then create vm backups with a screen image(I am not sure if a screen snapshot is supported in qemu now). This function is enabled in VMWARE which can automatically create full vm snapshots lively with a screen image which seems cool, so I want to introduce it to qemu. Limitations: currently only implemented "snapshotvm with_state internal live" case. no screen captured in the time of creating snapshots. no good integration with existing savevm, migration, snapshot_blkdev code. no test case yet. hmp/qmp API not added. Although there are so many gaps, but I want to send these patch first to make sure I am in the right direction, esp the implemention of savevm lively with vmstate, to see if there is potentional problem, such as creating snapshots takes too long? Other cases would be simpler if this case have no major problem found. Wenchao Xia (2): live backup vm, export functions live backup vm, snapshots all lively block.c | 21 ++++++ block.h | 2 + buffered_file.c | 106 +++++++++++++++++++++++++++ buffered_file.h | 1 + migration.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ migration.h | 13 ++++ savevm.c | 37 +++------- sysemu.h | 2 + 8 files changed, 371 insertions(+), 26 deletions(-) ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-08 8:24 [Qemu-devel] [RFC PATCH 0/2] live backup vm Wenchao Xia @ 2012-12-07 10:12 ` Dietmar Maurer 2012-12-09 4:37 ` Wenchao Xia 2012-12-08 8:24 ` [Qemu-devel] [RFC PATCH 1/2] live backup vm, export functions Wenchao Xia 2012-12-08 8:24 ` [Qemu-devel] [RFC PATCH 2/2] live backup vm, snapshots all lively Wenchao Xia 2 siblings, 1 reply; 15+ messages in thread From: Dietmar Maurer @ 2012-12-07 10:12 UTC (permalink / raw) To: Wenchao Xia, qemu-devel@nongnu.org Cc: kwolf@redhat.com, pbonzini@redhat.com, aliguori@us.ibm.com, blauwirbel@gmail.com, stefanha@gmail.com We already have a full functional implementation to create live snapshots including VM state. The interface allows you to create internal snapshots, or use external tools to create the blockdev snapshots directly on the underlying storage (we use that with nexenta). VM state is stored directly on a block device. https://git.proxmox.com/?p=pve-qemu-kvm.git;a=blob;f=debian/patches/internal-snapshot-async.patch;h=6c86de3a6160c58d77baa41a7774c4a80e63639e;hb=HEAD Unfortunately I had no time to cleanup those patches. - Dietmar > This patch is a scratch which enables a full live backup of VM, actually it is > equal to savevm lively. As a test it uses hmp command migrate to trigger the > action. > > The ultimate goal is providing another command to user as: > snapshotvm [with_state] [internal] [live] which then create vm backups with > a screen image(I am not sure if a screen snapshot is supported in qemu > now). This function is enabled in VMWARE which can automatically create > full vm snapshots lively with a screen image which seems cool, so I want to > introduce it to qemu. > > Limitations: > currently only implemented "snapshotvm with_state internal live" case. > no screen captured in the time of creating snapshots. > no good integration with existing savevm, migration, snapshot_blkdev code. > no test case yet. > hmp/qmp API not added. > > Although there are so many gaps, but I want to send these patch first to > make sure I am in the right direction, esp the implemention of savevm lively > with vmstate, to see if there is potentional problem, such as creating > snapshots takes too long? Other cases would be simpler if this case have no > major problem found. > > Wenchao Xia (2): > live backup vm, export functions > live backup vm, snapshots all lively > > block.c | 21 ++++++ > block.h | 2 + > buffered_file.c | 106 +++++++++++++++++++++++++++ > buffered_file.h | 1 + > migration.c | 215 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > migration.h | 13 ++++ > savevm.c | 37 +++------- > sysemu.h | 2 + > 8 files changed, 371 insertions(+), 26 deletions(-) > > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-07 10:12 ` Dietmar Maurer @ 2012-12-09 4:37 ` Wenchao Xia 2012-12-09 7:12 ` Dietmar Maurer 0 siblings, 1 reply; 15+ messages in thread From: Wenchao Xia @ 2012-12-09 4:37 UTC (permalink / raw) To: Dietmar Maurer Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, pbonzini@redhat.com 于 2012-12-7 18:12, Dietmar Maurer 写道: > We already have a full functional implementation to create live snapshots including VM state. > > The interface allows you to create internal snapshots, or use external tools to create the blockdev snapshots > directly on the underlying storage (we use that with nexenta). VM state is stored directly on a block device. > > https://git.proxmox.com/?p=pve-qemu-kvm.git;a=blob;f=debian/patches/internal-snapshot-async.patch;h=6c86de3a6160c58d77baa41a7774c4a80e63639e;hb=HEAD > > Unfortunately I had no time to cleanup those patches. > > - Dietmar > have that patch been sent to mail-list? I'll rebase that patch and take it as part of the API's implemention, if you agree. >> This patch is a scratch which enables a full live backup of VM, actually it is >> equal to savevm lively. As a test it uses hmp command migrate to trigger the >> action. >> >> The ultimate goal is providing another command to user as: >> snapshotvm [with_state] [internal] [live] which then create vm backups with >> a screen image(I am not sure if a screen snapshot is supported in qemu >> now). This function is enabled in VMWARE which can automatically create >> full vm snapshots lively with a screen image which seems cool, so I want to >> introduce it to qemu. >> >> Limitations: >> currently only implemented "snapshotvm with_state internal live" case. >> no screen captured in the time of creating snapshots. >> no good integration with existing savevm, migration, snapshot_blkdev code. >> no test case yet. >> hmp/qmp API not added. >> >> Although there are so many gaps, but I want to send these patch first to >> make sure I am in the right direction, esp the implemention of savevm lively >> with vmstate, to see if there is potentional problem, such as creating >> snapshots takes too long? Other cases would be simpler if this case have no >> major problem found. >> >> Wenchao Xia (2): >> live backup vm, export functions >> live backup vm, snapshots all lively >> >> block.c | 21 ++++++ >> block.h | 2 + >> buffered_file.c | 106 +++++++++++++++++++++++++++ >> buffered_file.h | 1 + >> migration.c | 215 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> migration.h | 13 ++++ >> savevm.c | 37 +++------- >> sysemu.h | 2 + >> 8 files changed, 371 insertions(+), 26 deletions(-) >> >> > > > -- Best Regards Wenchao Xia ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-09 4:37 ` Wenchao Xia @ 2012-12-09 7:12 ` Dietmar Maurer 2012-12-10 1:37 ` Wenchao Xia 0 siblings, 1 reply; 15+ messages in thread From: Dietmar Maurer @ 2012-12-09 7:12 UTC (permalink / raw) To: Wenchao Xia Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, pbonzini@redhat.com > > https://git.proxmox.com/?p=pve-qemu- > kvm.git;a=blob;f=debian/patches/in > > ternal-snapshot- > async.patch;h=6c86de3a6160c58d77baa41a7774c4a80e63639e > > ;hb=HEAD > > > > Unfortunately I had no time to cleanup those patches. > > > > - Dietmar > > > have that patch been sent to mail-list? I'll rebase that patch and take it as > part of the API's implemention, if you agree. Sorry, as mentioned above I had no time to cleanup those patches so far. My plan is to send them early next year. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-09 7:12 ` Dietmar Maurer @ 2012-12-10 1:37 ` Wenchao Xia 2012-12-10 6:23 ` Dietmar Maurer 0 siblings, 1 reply; 15+ messages in thread From: Wenchao Xia @ 2012-12-10 1:37 UTC (permalink / raw) To: Dietmar Maurer Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, pbonzini@redhat.com 于 2012-12-9 15:12, Dietmar Maurer 写道: >>> https://git.proxmox.com/?p=pve-qemu- >> kvm.git;a=blob;f=debian/patches/in >>> ternal-snapshot- >> async.patch;h=6c86de3a6160c58d77baa41a7774c4a80e63639e >>> ;hb=HEAD >>> >>> Unfortunately I had no time to cleanup those patches. >>> >>> - Dietmar >>> >> have that patch been sent to mail-list? I'll rebase that patch and take it as >> part of the API's implemention, if you agree. > > Sorry, as mentioned above I had no time to cleanup those patches so far. My plan is > to send them early next year. > I can do the clean up or rebase from the url you have given, and include them as part of my serials. Just want to avoid conflict between your patch next year and mine by include yours as sub patches. :) -- Best Regards Wenchao Xia ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-10 1:37 ` Wenchao Xia @ 2012-12-10 6:23 ` Dietmar Maurer 2012-12-11 7:14 ` Wenchao Xia 0 siblings, 1 reply; 15+ messages in thread From: Dietmar Maurer @ 2012-12-10 6:23 UTC (permalink / raw) To: Wenchao Xia Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, pbonzini@redhat.com > I can do the clean up or rebase from the url you have given, and include > them as part of my serials. Just want to avoid conflict between your patch > next year and mine by include yours as sub patches. :) That would be great. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-10 6:23 ` Dietmar Maurer @ 2012-12-11 7:14 ` Wenchao Xia 2012-12-11 7:46 ` Dietmar Maurer 0 siblings, 1 reply; 15+ messages in thread From: Wenchao Xia @ 2012-12-11 7:14 UTC (permalink / raw) To: Dietmar Maurer Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, pbonzini@redhat.com 于 2012-12-10 14:23, Dietmar Maurer 写道: >> I can do the clean up or rebase from the url you have given, and include >> them as part of my serials. Just want to avoid conflict between your patch >> next year and mine by include yours as sub patches. :) > > That would be great. > I have read the code from the link, it seems it does two things, I will break them into two parts: 1 create internal snapshots for a single device. 2 save/load vmstate in an specified image file that qemu support. Have some questions: in qmp_savevm_start(), vm_stop(RUN_STATE_SAVE_VM), I think this will stop the VM running make it not lively, am I right? -- Best Regards Wenchao Xia ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-11 7:14 ` Wenchao Xia @ 2012-12-11 7:46 ` Dietmar Maurer 2012-12-12 2:16 ` Wenchao Xia 2012-12-12 8:30 ` Paolo Bonzini 0 siblings, 2 replies; 15+ messages in thread From: Dietmar Maurer @ 2012-12-11 7:46 UTC (permalink / raw) To: Wenchao Xia Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, pbonzini@redhat.com OK, I will try to give a short overview on the functionality. First, we decided to use 'internal' snapshots for our 'live snapshot' implementation. Internal snapshots almost always use some kind of reference counting, making snapshot action (like 'create/delete snapshot') quite efficient and fast. Internal snapshot totally depends on the storage backend. For now we can create internal snapshots on the following storage backend: * qcow2 files * rbd * sheepdog * nexenta iscsi As you can see, creating internal snapshots sometimes needs external tool. For example we use the nexenta API to create snapshots, while we use libiscsi to access them inside qemu. So our snapshot implementation uses the following steps: 1.) qmp: savevm-start [statefile] This save the VM state into [statefile] and then stops the VM. 2.) qga freezefs 3.) create snapshots: either using external tools or by qmp: snapshot-drive 4.) gqa unfreezefs 5.) qmp: savevm-end This restarts/resumes the VM > Have some questions: > in qmp_savevm_start(), vm_stop(RUN_STATE_SAVE_VM), I think this will > stop the VM running make it not lively, am I right? Yes, we need to halt the VM for a short period of time while we make snapshots. But that time is usually short. - Dietmar ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-11 7:46 ` Dietmar Maurer @ 2012-12-12 2:16 ` Wenchao Xia 2012-12-12 8:30 ` Paolo Bonzini 1 sibling, 0 replies; 15+ messages in thread From: Wenchao Xia @ 2012-12-12 2:16 UTC (permalink / raw) To: Dietmar Maurer Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, pbonzini@redhat.com OK, I'll adjust the code into the upstream framework, thanks for your declaration. > OK, I will try to give a short overview on the functionality. > > First, we decided to use 'internal' snapshots for our 'live snapshot' implementation. > Internal snapshots almost always use some kind of reference counting, making > snapshot action (like 'create/delete snapshot') quite efficient and fast. > > Internal snapshot totally depends on the storage backend. For now we can create > internal snapshots on the following storage backend: > > * qcow2 files > * rbd > * sheepdog > * nexenta iscsi > > As you can see, creating internal snapshots sometimes needs external tool. For example we use the > nexenta API to create snapshots, while we use libiscsi to access them inside qemu. > > So our snapshot implementation uses the following steps: > > 1.) qmp: savevm-start [statefile] > > This save the VM state into [statefile] and then stops the VM. > > 2.) qga freezefs > > 3.) create snapshots: either using external tools or by qmp: snapshot-drive > > 4.) gqa unfreezefs > > 5.) qmp: savevm-end > > This restarts/resumes the VM > >> Have some questions: >> in qmp_savevm_start(), vm_stop(RUN_STATE_SAVE_VM), I think this will >> stop the VM running make it not lively, am I right? > > Yes, we need to halt the VM for a short period of time while we make > snapshots. But that time is usually short. > > - Dietmar > -- Best Regards Wenchao Xia ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-11 7:46 ` Dietmar Maurer 2012-12-12 2:16 ` Wenchao Xia @ 2012-12-12 8:30 ` Paolo Bonzini 2012-12-12 8:50 ` Dietmar Maurer 2012-12-12 9:03 ` Dietmar Maurer 1 sibling, 2 replies; 15+ messages in thread From: Paolo Bonzini @ 2012-12-12 8:30 UTC (permalink / raw) To: Dietmar Maurer Cc: kwolf, aliguori, stefanha, qemu-devel, blauwirbel, Wenchao Xia > So our snapshot implementation uses the following steps: > > 1.) qmp: savevm-start [statefile] > > This save the VM state into [statefile] and then stops the VM. That's migrate exec:cat>statefile (or similar) > 2.) qga freezefs How can freezefs run while the VM is stopped? > 3.) create snapshots: either using external tools or by qmp: > snapshot-drive > > 4.) gqa unfreezefs Same as above, this should be done after step (5). > 5.) qmp: savevm-end > > This restarts/resumes the VM That's simply "cont". Paolo ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-12 8:30 ` Paolo Bonzini @ 2012-12-12 8:50 ` Dietmar Maurer 2012-12-12 9:03 ` Dietmar Maurer 1 sibling, 0 replies; 15+ messages in thread From: Dietmar Maurer @ 2012-12-12 8:50 UTC (permalink / raw) To: Paolo Bonzini Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, Wenchao Xia > > 1.) qmp: savevm-start [statefile] > > > > This save the VM state into [statefile] and then stops the VM. > > That's migrate exec:cat>statefile (or similar) Basic functionality is the same, but we support saving state to block devices. But there are many migration related patches in the last months, so I decide to not touch that code for now, and write my own. But yes, in future, we can try to merge things. > > 2.) qga freezefs > > How can freezefs run while the VM is stopped? Oh, good point ;-) So we need to call that inside savevm-start > > 3.) create snapshots: either using external tools or by qmp: > > snapshot-drive > > > > 4.) gqa unfreezefs > > Same as above, this should be done after step (5). yes > > 5.) qmp: savevm-end > > > > This restarts/resumes the VM > > That's simply "cont". Yes - the plan was to do extra checks here. If it is not needed, we can remove it later. I also want to avoid that a user can resume a VM which was suspended for taking snapshots, but I am not sure how to do that. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-12 8:30 ` Paolo Bonzini 2012-12-12 8:50 ` Dietmar Maurer @ 2012-12-12 9:03 ` Dietmar Maurer 2012-12-12 10:00 ` Paolo Bonzini 1 sibling, 1 reply; 15+ messages in thread From: Dietmar Maurer @ 2012-12-12 9:03 UTC (permalink / raw) To: Paolo Bonzini Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com, qemu-devel@nongnu.org, blauwirbel@gmail.com, Wenchao Xia > > So our snapshot implementation uses the following steps: > > > > 1.) qmp: savevm-start [statefile] > > > > This save the VM state into [statefile] and then stops the VM. > > That's migrate exec:cat>statefile (or similar) We save to block devices, so we need to allocate them in advance with a size of 2 x 'memory size'. So we have an upper limit for the state file file, i.e. we stop the VM if ('statefile size' > 'assigned memory'). It would be great to have some other means to reduce state size (instead of stopping the VM), for example by slowing down the VM somehow? Any other ideas? ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] live backup vm 2012-12-12 9:03 ` Dietmar Maurer @ 2012-12-12 10:00 ` Paolo Bonzini 0 siblings, 0 replies; 15+ messages in thread From: Paolo Bonzini @ 2012-12-12 10:00 UTC (permalink / raw) To: Dietmar Maurer Cc: kwolf@redhat.com, stefanha@gmail.com, aliguori@us.ibm.com, qemu-devel@nongnu.org, blauwirbel@gmail.com Il 12/12/2012 10:03, Dietmar Maurer ha scritto: >>> So our snapshot implementation uses the following steps: >>> >>> 1.) qmp: savevm-start [statefile] >>> >>> This save the VM state into [statefile] and then stops the VM. >> >> That's migrate exec:cat>statefile (or similar) > > We save to block devices, so we need to allocate them in advance > with a size of 2 x 'memory size'. > So we have an upper limit for the state file file, i.e. we stop the > VM if ('statefile size' > 'assigned memory'). This is a heuristic that we can add (though remember you'll need some extra space for the device state). > It would be great to have some other means to reduce state size (instead > of stopping the VM), for example by slowing down the VM somehow? Yes, you can use the cpu cgroup. Paolo > Any other ideas? > ^ permalink raw reply [flat|nested] 15+ messages in thread
* [Qemu-devel] [RFC PATCH 1/2] live backup vm, export functions 2012-12-08 8:24 [Qemu-devel] [RFC PATCH 0/2] live backup vm Wenchao Xia 2012-12-07 10:12 ` Dietmar Maurer @ 2012-12-08 8:24 ` Wenchao Xia 2012-12-08 8:24 ` [Qemu-devel] [RFC PATCH 2/2] live backup vm, snapshots all lively Wenchao Xia 2 siblings, 0 replies; 15+ messages in thread From: Wenchao Xia @ 2012-12-08 8:24 UTC (permalink / raw) To: qemu-devel Cc: kwolf, aliguori, stefanha, Wenchao Xia, blauwirbel, pbonzini, dietmar This patch moved bdrv_snapshot_find() from savevm.c to block.c, also exports some function in savevm.c. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- block.c | 21 +++++++++++++++++++++ block.h | 2 ++ savevm.c | 37 +++++++++++-------------------------- sysemu.h | 2 ++ 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/block.c b/block.c index c05875f..155b562 100644 --- a/block.c +++ b/block.c @@ -3322,6 +3322,27 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) return buf; } +int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, + const char *name) +{ + QEMUSnapshotInfo *sn_tab, *sn; + int nb_sns, i, ret; + + ret = -ENOENT; + nb_sns = bdrv_snapshot_list(bs, &sn_tab); + if (nb_sns < 0) + return ret; + for(i = 0; i < nb_sns; i++) { + sn = &sn_tab[i]; + if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { + *sn_info = *sn; + ret = 0; + break; + } + } + g_free(sn_tab); + return ret; +} /**************************************************************/ /* async I/Os */ diff --git a/block.h b/block.h index 722c620..0838736 100644 --- a/block.h +++ b/block.h @@ -330,6 +330,8 @@ int bdrv_snapshot_list(BlockDriverState *bs, int bdrv_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name); char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); +int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, + const char *name); char *get_human_readable_size(char *buf, int buf_size, int64_t size); int path_is_absolute(const char *path); diff --git a/savevm.c b/savevm.c index 5d04d59..e1bad85 100644 --- a/savevm.c +++ b/savevm.c @@ -698,7 +698,7 @@ int qemu_get_byte(QEMUFile *f) return result; } -static int64_t qemu_ftell(QEMUFile *f) +int64_t qemu_ftell(QEMUFile *f) { return f->buf_offset - f->buf_size + f->buf_index; } @@ -2061,32 +2061,10 @@ out: return ret; } -static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, - const char *name) -{ - QEMUSnapshotInfo *sn_tab, *sn; - int nb_sns, i, ret; - - ret = -ENOENT; - nb_sns = bdrv_snapshot_list(bs, &sn_tab); - if (nb_sns < 0) - return ret; - for(i = 0; i < nb_sns; i++) { - sn = &sn_tab[i]; - if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { - *sn_info = *sn; - ret = 0; - break; - } - } - g_free(sn_tab); - return ret; -} - /* * Deletes snapshots of a given name in all opened images. */ -static int del_existing_snapshots(Monitor *mon, const char *name) +int del_existing_snapshots(Monitor *mon, Error **errp, const char *name) { BlockDriverState *bs; QEMUSnapshotInfo sn1, *snapshot = &sn1; @@ -2099,9 +2077,16 @@ static int del_existing_snapshots(Monitor *mon, const char *name) { ret = bdrv_snapshot_delete(bs, name); if (ret < 0) { - monitor_printf(mon, + if (mon != NULL) { + monitor_printf(mon, "Error while deleting snapshot on '%s'\n", bdrv_get_device_name(bs)); + } + if (errp != NULL) { + error_setg(errp, + "Error while deleting snapshot on '%s'\n", + bdrv_get_device_name(bs)); + } return -1; } } @@ -2186,7 +2171,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) } /* Delete old snapshots of the same name */ - if (name && del_existing_snapshots(mon, name) < 0) { + if (name && del_existing_snapshots(mon, NULL, name) < 0) { goto the_end; } diff --git a/sysemu.h b/sysemu.h index f5ac664..f44f9ee 100644 --- a/sysemu.h +++ b/sysemu.h @@ -69,6 +69,8 @@ void do_savevm(Monitor *mon, const QDict *qdict); int load_vmstate(const char *name); void do_delvm(Monitor *mon, const QDict *qdict); void do_info_snapshots(Monitor *mon); +int del_existing_snapshots(Monitor *mon, Error **errp, const char *name); +int64_t qemu_ftell(QEMUFile *f); void qemu_announce_self(void); -- 1.7.1 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [RFC PATCH 2/2] live backup vm, snapshots all lively 2012-12-08 8:24 [Qemu-devel] [RFC PATCH 0/2] live backup vm Wenchao Xia 2012-12-07 10:12 ` Dietmar Maurer 2012-12-08 8:24 ` [Qemu-devel] [RFC PATCH 1/2] live backup vm, export functions Wenchao Xia @ 2012-12-08 8:24 ` Wenchao Xia 2 siblings, 0 replies; 15+ messages in thread From: Wenchao Xia @ 2012-12-08 8:24 UTC (permalink / raw) To: qemu-devel Cc: kwolf, aliguori, stefanha, Wenchao Xia, blauwirbel, pbonzini, dietmar This patch uses a tricky to do live migration to local block images, and then create internal snapshots. So basically this patch connect function in live migration and savevm to get a full live back effect. In monitor, type migrate image: to trigger this action for a test. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- buffered_file.c | 106 +++++++++++++++++++++++++++ buffered_file.h | 1 + migration.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ migration.h | 13 ++++ 4 files changed, 335 insertions(+), 0 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index bd0f61d..63284ed 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -267,3 +267,109 @@ QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state) return s->file; } + +/* image operations */ + +static int image_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) +{ + QEMUFileBuffered *s = opaque; + BlockDriverState *bds = s->migration_state->image.bds; + ssize_t error; + + DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); + + error = qemu_file_get_error(s->file); + if (error) { + DPRINTF("flush when error, bailing: %s\n", strerror(-error)); + return error; + } + + DPRINTF("unfreezing output\n"); + s->freeze_output = 0; + + /* no buffer is used, so speed limit is not accurate but a memcpy is saved, + will buffer increase performance in this case? */ + if (size > 0) { + error = bdrv_save_vmstate(bds, buf, pos, size); + if (error < 0) { + DPRINTF("bdrv_save_vmstate error, bailing: %s\n", + strerror(-error)); + return error; + } + s->bytes_xfer += size; + } + + if (pos == 0 && size == 0) { + DPRINTF("file is ready\n"); + if (!s->freeze_output && s->bytes_xfer < s->xfer_limit) { + DPRINTF("notifying client\n"); + migrate_image_put_ready(s->migration_state); + } + } + + return size; +} + +static int image_close(void *opaque) +{ + QEMUFileBuffered *s = opaque; + BlockDriverState *bds = s->migration_state->image.bds; + int ret = 0; + + DPRINTF("closing\n"); + s->xfer_limit = INT_MAX; + ret = bdrv_flush(bds); + + qemu_del_timer(s->timer); + qemu_free_timer(s->timer); + g_free(s->buffer); + g_free(s); + + return ret; +} + +static const QEMUFileOps image_file_ops = { + .get_fd = NULL, + .put_buffer = image_put_buffer, + .close = image_close, + .rate_limit = buffered_rate_limit, + .get_rate_limit = buffered_get_rate_limit, + .set_rate_limit = buffered_set_rate_limit, +}; + +static void image_rate_tick(void *opaque) +{ + QEMUFileBuffered *s = opaque; + + if (qemu_file_get_error(s->file)) { + buffered_close(s); + return; + } + + qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100); + + if (s->freeze_output) + return; + + s->bytes_xfer = 0; + + image_put_buffer(s, NULL, 0, 0); +} + +QEMUFile *qemu_fopen_ops_image(MigrationState *migration_state) +{ + QEMUFileBuffered *s; + + s = g_malloc0(sizeof(*s)); + + s->migration_state = migration_state; + s->xfer_limit = migration_state->bandwidth_limit / 10; + + s->file = qemu_fopen_ops(s, &image_file_ops); + + s->timer = qemu_new_timer_ms(rt_clock, image_rate_tick, s); + + qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 100); + + return s->file; +} diff --git a/buffered_file.h b/buffered_file.h index ef010fe..8c02b1a 100644 --- a/buffered_file.h +++ b/buffered_file.h @@ -18,5 +18,6 @@ #include "migration.h" QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state); +QEMUFile *qemu_fopen_ops_image(MigrationState *migration_state); #endif diff --git a/migration.c b/migration.c index 73ce170..385cafd 100644 --- a/migration.c +++ b/migration.c @@ -524,6 +524,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, s = migrate_init(¶ms); + if (strstart(uri, "tcp:", &p)) { tcp_start_outgoing_migration(s, p, &local_err); #if !defined(WIN32) @@ -534,6 +535,16 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, } else if (strstart(uri, "fd:", &p)) { fd_start_outgoing_migration(s, p, &local_err); #endif + } else if (strstart(uri, "image:", &p)) { + /* a direct hack to test migration to image */ + migrate_image_prepare(s, NULL, &local_err); + if (local_err) { + migrate_image_error(s); + error_propagate(errp, local_err); + return; + } + migrate_image_start(s); + printf("start migrate to image.\n"); } else { error_set(errp, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); return; @@ -609,3 +620,207 @@ int64_t migrate_xbzrle_cache_size(void) return s->xbzrle_cache_size; } + +/* migration to image helpers */ + +static int migrate_image_cleanup(MigrationState *s) +{ + int ret = 0; + + if (s->file) { + DPRINTF("closing file\n"); + ret = qemu_fclose(s->file); + s->file = NULL; + } + + return ret; +} + +static int migrate_image_snapshot_create(MigrationState *s, Error **errp) +{ + BlockDriverState *bs = s->image.bds, *bs1; + QEMUSnapshotInfo *sn = &s->image.sn; + int vm_state_size = qemu_ftell(s->file); + int ret = 0; + + /* create the snapshots */ + + bs1 = NULL; + while ((bs1 = bdrv_next(bs1))) { + if (bdrv_can_snapshot(bs1)) { + /* Write VM state size only to the image that contains the state */ + sn->vm_state_size = (bs == bs1 ? vm_state_size : 0); + ret = bdrv_snapshot_create(bs1, sn); + if (ret < 0) { + if (errp != NULL) { + error_setg(errp, + "Error while creating snapshot on '%s'\n", + bdrv_get_device_name(bs1)); + } + ret = -1; + } + } + } + return ret; +} + +void migrate_image_error(MigrationState *s) +{ + DPRINTF("setting error state\n"); + s->state = MIG_STATE_ERROR; + notifier_list_notify(&migration_state_notifiers, s); + migrate_image_cleanup(s); +} + +static void migrate_image_completed(MigrationState *s) +{ + DPRINTF("setting completed state\n"); + if (migrate_image_cleanup(s) < 0) { + s->state = MIG_STATE_ERROR; + } else { + s->state = MIG_STATE_COMPLETED; + runstate_set(RUN_STATE_POSTMIGRATE); + } + notifier_list_notify(&migration_state_notifiers, s); +} + +void migrate_image_put_ready(MigrationState *s) +{ + int ret; + + if (s->state != MIG_STATE_ACTIVE) { + DPRINTF("put_ready returning because of non-active state\n"); + return; + } + + DPRINTF("iterate\n"); + ret = qemu_savevm_state_iterate(s->file); + if (ret < 0) { + DPRINTF("failed in savevm iterate.\n"); + migrate_image_error(s); + } else if (ret == 1) { + int old_vm_running = runstate_is_running(); + int64_t start_time, end_time; + + DPRINTF("done iterating\n"); + start_time = qemu_get_clock_ms(rt_clock); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + + if ((qemu_savevm_state_complete(s->file) >= 0) && + (migrate_image_snapshot_create(s, NULL) >= 0)) { + migrate_image_completed(s); + + } else { + migrate_image_error(s); + } + + end_time = qemu_get_clock_ms(rt_clock); + s->total_time = end_time - s->total_time; + s->downtime = end_time - start_time; + if (old_vm_running) { + vm_start(); + } + } +} + +void migrate_image_prepare(MigrationState *s, const char *name, Error **errp) +{ + BlockDriverState *bs; + QEMUSnapshotInfo *sn = &s->image.sn, old_sn1, *old_sn = &old_sn1; + int ret, saved_vm_running; + test_ms = s; +#ifdef _WIN32 + struct _timeb tb; + struct tm *ptm; +#else + struct timeval tv; + struct tm tm; +#endif + + bs = NULL; + while ((bs = bdrv_next(bs))) { + + if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { + continue; + } + + if (!bdrv_can_snapshot(bs)) { + error_setg(errp, + "Device '%s' is writable but does not support snapshots.\n", + bdrv_get_device_name(bs)); + return; + } + } + + bs = bdrv_snapshots(); + if (!bs) { + error_setg(errp, "No block device can accept snapshots\n"); + return; + } + s->image.bds = bs; + + saved_vm_running = runstate_is_running(); + vm_stop(RUN_STATE_SAVE_VM); + + memset(sn, 0, sizeof(*sn)); + + /* fill auxiliary fields */ +#ifdef _WIN32 + _ftime(&tb); + sn->date_sec = tb.time; + sn->date_nsec = tb.millitm * 1000000; +#else + gettimeofday(&tv, NULL); + sn->date_sec = tv.tv_sec; + sn->date_nsec = tv.tv_usec * 1000; +#endif + sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); + + if (name) { + ret = bdrv_snapshot_find(bs, old_sn, name); + if (ret >= 0) { + pstrcpy(sn->name, sizeof(sn->name), old_sn->name); + pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); + } else { + pstrcpy(sn->name, sizeof(sn->name), name); + } + } else { +#ifdef _WIN32 + time_t t = tb.time; + ptm = localtime(&t); + strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm); +#else + /* cast below needed for OpenBSD where tv_sec is still 'long' */ + localtime_r((const time_t *)&tv.tv_sec, &tm); + strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm); +#endif + } + + /* Delete old snapshots of the same name */ + if (name && del_existing_snapshots(NULL, errp, name) < 0) { + goto the_end; + } + + the_end: + if (saved_vm_running) + vm_start(); + return; +} + +void migrate_image_start(MigrationState *s) +{ + int ret; + + s->state = MIG_STATE_ACTIVE; + s->file = qemu_fopen_ops_image(s); + + DPRINTF("beginning savevm\n"); + ret = qemu_savevm_state_begin(s->file, &s->params); + if (ret < 0) { + DPRINTF("failed, %d\n", ret); + migrate_image_error(s); + return; + } + migrate_image_put_ready(s); +} diff --git a/migration.h b/migration.h index c3a23cc..f2308c3 100644 --- a/migration.h +++ b/migration.h @@ -20,6 +20,7 @@ #include "error.h" #include "vmstate.h" #include "qapi-types.h" +#include "block.h" struct MigrationParams { bool blk; @@ -28,6 +29,13 @@ struct MigrationParams { typedef struct MigrationState MigrationState; +struct MigrationImage { + BlockDriverState *bds; + QEMUSnapshotInfo sn; +}; + +typedef struct MigrationImage MigrationImage; + struct MigrationState { int64_t bandwidth_limit; @@ -45,6 +53,7 @@ struct MigrationState int64_t dirty_pages_rate; bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; + MigrationImage image; }; void process_incoming_migration(QEMUFile *f); @@ -128,4 +137,8 @@ int64_t migrate_xbzrle_cache_size(void); int64_t xbzrle_cache_resize(int64_t new_size); +void migrate_image_error(MigrationState *s); +void migrate_image_prepare(MigrationState *s, const char *name, Error **errp); +void migrate_image_start(MigrationState *s); +void migrate_image_put_ready(MigrationState *s); #endif -- 1.7.1 ^ permalink raw reply related [flat|nested] 15+ messages in thread
end of thread, other threads:[~2012-12-12 10:01 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-12-08 8:24 [Qemu-devel] [RFC PATCH 0/2] live backup vm Wenchao Xia 2012-12-07 10:12 ` Dietmar Maurer 2012-12-09 4:37 ` Wenchao Xia 2012-12-09 7:12 ` Dietmar Maurer 2012-12-10 1:37 ` Wenchao Xia 2012-12-10 6:23 ` Dietmar Maurer 2012-12-11 7:14 ` Wenchao Xia 2012-12-11 7:46 ` Dietmar Maurer 2012-12-12 2:16 ` Wenchao Xia 2012-12-12 8:30 ` Paolo Bonzini 2012-12-12 8:50 ` Dietmar Maurer 2012-12-12 9:03 ` Dietmar Maurer 2012-12-12 10:00 ` Paolo Bonzini 2012-12-08 8:24 ` [Qemu-devel] [RFC PATCH 1/2] live backup vm, export functions Wenchao Xia 2012-12-08 8:24 ` [Qemu-devel] [RFC PATCH 2/2] live backup vm, snapshots all lively Wenchao Xia
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).