Re: [Qemu-devel] [PATCH v5 6/6] add vm state to backups
First pass, concentrating on interfaces, implementation mostly ignored. Dietmar Maurer diet...@proxmox.com writes: Signed-off-by: Dietmar Maurer diet...@proxmox.com --- blockdev.c | 196 +- hmp.c|3 +- qapi-schema.json |5 +- 3 files changed, 200 insertions(+), 4 deletions(-) [...] diff --git a/hmp.c b/hmp.c index b2c1f23..370cdf8 100644 --- a/hmp.c +++ b/hmp.c @@ -1052,7 +1052,8 @@ void hmp_backup(Monitor *mon, const QDict *qdict) Error *errp = NULL; qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist, - devlist, qdict_haskey(qdict, speed), speed, errp); + devlist, qdict_haskey(qdict, speed), speed, false, false, + errp); if (error_is_set(errp)) { monitor_printf(mon, %s\n, error_get_pretty(errp)); Feature not available in HMP. You could add a flag argument to provide it. diff --git a/qapi-schema.json b/qapi-schema.json index 09ca8ef..1fabb67 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1885,6 +1885,8 @@ # @devlist: #optional list of block device names (separated by ',', ';' # or ':'). By default the backup includes all writable block devices. # +# @state: #optional flag to include vm state +# This isn't a state. Suggest to call it @save_vmstate or similar. # Returns: the uuid of the backup job # # Since: 1.5.0 @@ -1892,7 +1894,8 @@ { 'command': 'backup', 'data': { 'backup-file': 'str', '*format': 'BackupFormat', '*config-file': 'str', - '*devlist': 'str', '*speed': 'int' }, + '*devlist': 'str', '*speed': 'int', + '*state': 'bool' }, 'returns': 'str' } ##
Re: [Qemu-devel] [PATCH v5 6/6] add vm state to backups
First pass, concentrating on interfaces, implementation mostly ignored. Hi Markus, many thanks for the review. I currently try to rewrite the whole series using and nbd server - like suggested by Stefan. So hmp/qmp commands will change.
Re: [Qemu-devel] [PATCH v5 6/6] add vm state to backups
On 02/27/2013 04:59 AM, Markus Armbruster wrote: First pass, concentrating on interfaces, implementation mostly ignored. Dietmar Maurer diet...@proxmox.com writes: Signed-off-by: Dietmar Maurer diet...@proxmox.com --- +# @state: #optional flag to include vm state +# This isn't a state. Suggest to call it @save_vmstate or similar. Actually, @save-vmstate (prefer '-' over '_' in QMP) -- Eric Blake eblake redhat com+1-919-301-3266 Libvirt virtualization library http://libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PATCH v5 6/6] add vm state to backups
Eric Blake ebl...@redhat.com writes: On 02/27/2013 04:59 AM, Markus Armbruster wrote: First pass, concentrating on interfaces, implementation mostly ignored. Dietmar Maurer diet...@proxmox.com writes: Signed-off-by: Dietmar Maurer diet...@proxmox.com --- +# @state: #optional flag to include vm state +# This isn't a state. Suggest to call it @save_vmstate or similar. Actually, @save-vmstate (prefer '-' over '_' in QMP) Yes; thanks for correcting my typo.
[Qemu-devel] [PATCH v5 6/6] add vm state to backups
Signed-off-by: Dietmar Maurer diet...@proxmox.com --- blockdev.c | 196 +- hmp.c|3 +- qapi-schema.json |5 +- 3 files changed, 200 insertions(+), 4 deletions(-) diff --git a/blockdev.c b/blockdev.c index 683f7da..dd20631 100644 --- a/blockdev.c +++ b/blockdev.c @@ -22,6 +22,8 @@ #include sysemu/arch_init.h #include backup.h #include vma.h +#include migration/qemu-file.h +#include migration/migration.h static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); @@ -1355,6 +1357,10 @@ static struct GenericBackupState { size_t total; size_t transferred; size_t zero_bytes; +unsigned char buf[BACKUP_CLUSTER_SIZE]; +int buf_index; +size_t buf_cluster_num; +guint8 vmstate_dev_id; } backup_state; typedef struct BackupCB { @@ -1510,10 +1516,170 @@ static void backup_start_jobs(void) backup_run_next_job(); } +static int backup_state_close(void *opaque) +{ +if (!backup_state.buf_index) { +return 0; +} + +size_t zero_bytes = 0; +if (backup_state.buf_index BACKUP_CLUSTER_SIZE) { +memset(backup_state.buf + backup_state.buf_index, 0, + BACKUP_CLUSTER_SIZE - backup_state.buf_index); +} +int bytes = backup_state.driver-dump( +backup_state.writer, backup_state.vmstate_dev_id, +backup_state.buf_cluster_num, +backup_state.buf, zero_bytes); +backup_state.buf_index = 0; + +return bytes 0 ? -1 : 0; +} + +static int backup_state_put_buffer(void *opaque, const uint8_t *buf, + int64_t pos, int size) +{ +assert(backup_state.driver); +assert(backup_state.writer); +assert(backup_state.driver-dump); + +/* Note: our backup driver expects to get whole clusters (64KB) */ + +int ret = size; + +while (size 0) { +int l = BACKUP_CLUSTER_SIZE - backup_state.buf_index; +l = l size ? size : l; +memcpy(backup_state.buf + backup_state.buf_index, buf, l); +backup_state.buf_index += l; +buf += l; +size -= l; +if (backup_state.buf_index == BACKUP_CLUSTER_SIZE) { +size_t zero_bytes = 0; +int bytes = backup_state.driver-dump( +backup_state.writer, backup_state.vmstate_dev_id, +backup_state.buf_cluster_num++, +backup_state.buf, zero_bytes); +backup_state.buf_index = 0; +if (bytes 0) { +return -1; +} +} +} + +return ret; +} + +static const QEMUFileOps backup_file_ops = { +.put_buffer = backup_state_put_buffer, +.close = backup_state_close, +}; + +static void coroutine_fn backup_start_savevm(void *opaque) +{ +assert(backup_state.driver); +assert(backup_state.writer); +int ret; +char *err = NULL; +uint64_t remaining; +int64_t maxlen; +MigrationParams params = { +.blk = 0, +.shared = 0 +}; + +int restart = 0; + +QEMUFile *file = qemu_fopen_ops(NULL, backup_file_ops); + +ret = qemu_savevm_state_begin(file, params); +if (ret 0) { +qemu_fclose(file); +err = g_strdup(qemu_savevm_state_begin failed); +goto abort; +} + +while (1) { +ret = qemu_savevm_state_iterate(file); +remaining = ram_bytes_remaining(); + +if (ret 0) { +qemu_fclose(file); +err = g_strdup_printf(qemu_savevm_state_iterate error %d, ret); +goto abort; +} + +/* stop the VM if we use too much space, + * or if remaining is just a few MB + */ +maxlen = ram_bytes_total(); +size_t cpos = backup_state.buf_cluster_num * BACKUP_CLUSTER_SIZE; +if ((remaining 10) || ((cpos + remaining) = maxlen)) { +if (runstate_is_running()) { +restart = 1; +vm_stop(RUN_STATE_SAVE_VM); + } +} + +if (ret == 1) { /* finished */ +if (runstate_is_running()) { +restart = 1; +vm_stop(RUN_STATE_SAVE_VM); +} + +ret = qemu_savevm_state_complete(file); +if (ret 0) { +qemu_fclose(file); +err = g_strdup(qemu_savevm_state_complete error); +goto abort; + +} else { +if (qemu_fclose(file) 0) { +error_setg(backup_state.error, + backup_start_savevm: qemu_fclose failed); +goto abort; +} +if (backup_state.driver-complete(backup_state.writer, +backup_state.vmstate_dev_id, 0) 0) { +err = g_strdup(backup_start_savevm: complete failed); +goto abort; +} +backup_run_next_job(); +goto out; +