Re: [Qemu-devel] [PATCH v5 6/6] add vm state to backups

2013-02-27 Thread Markus Armbruster
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

2013-02-27 Thread Dietmar Maurer
 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

2013-02-27 Thread Eric Blake
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

2013-02-27 Thread Markus Armbruster
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

2013-02-21 Thread Dietmar Maurer

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;
+