commit 93e0b3c8d665a7cc1ea3267a1e60868f633f51c2
Author: Daniel P. Berrange <berrange@redhat.com>
Date:   Wed Apr 21 14:06:37 2010 +0100

    Fix QEMU save/restore with block devices
    
    The save process was relying on use of the shell >> append
    operator to ensure the save data was placed after the libvirt
    header + XML. This doesn't work for block devices though.
    Replace this code with use of 'dd' and its 'seek' parameter.
    This means that we need to pad the header + XML out to a
    multiple of dd block size (in this case we choose 512).
    
    The qemuMonitorMigateToCommand() monitor API is used for both
    save/coredump, and migration via UNIX socket. We can't simply
    switch this to use 'dd' since this causes problems with the
    migration usage. Thus, create a dedicated qemuMonitorMigateToFile
    which can accept an filename + offset, and remove the filename
    from the current qemuMonitorMigateToCommand() API
    
    * src/qemu/qemu_driver.c: Switch to qemuMonitorMigateToFile
      for save and core dump
    * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
      src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h,
      src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h: Create
      a new qemuMonitorMigateToFile, separate from the existing
      qemuMonitorMigateToCommand to allow handling file offsets

Index: libvirt-0.7.6/src/qemu/qemu_driver.c
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_driver.c
+++ libvirt-0.7.6/src/qemu/qemu_driver.c
@@ -3896,7 +3896,8 @@ static int qemudDomainSave(virDomainPtr
     int rc;
     virDomainEventPtr event = NULL;
     qemuDomainObjPrivatePtr priv;
-    
+    unsigned long long offset;
+
     memset(&header, 0, sizeof(header));
     memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
     header.version = QEMUD_SAVE_VERSION;
@@ -3955,6 +3956,25 @@ static int qemudDomainSave(virDomainPtr
         goto endjob;
     }
     header.xml_len = strlen(xml) + 1;
+    offset = sizeof(header) + header.xml_len;
+
+    /* Due to way we append QEMU state on our header with dd,
+     * we need to ensure there's a 512 byte boundary. Unfortunately
+     * we don't have an explicit offset in the header, so we fake
+     * it by padding the XML string with NULLs */
+    if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
+        unsigned long long pad =
+            QEMU_MONITOR_MIGRATE_TO_FILE_BS -
+            (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS);
+
+        if (VIR_REALLOC_N(xml, header.xml_len + pad) < 0) {
+            virReportOOMError(dom->conn);
+            goto endjob;
+        }
+        memset(xml + header.xml_len, 0, pad);
+        offset += pad;
+        header.xml_len += pad;
+    }
 
     /* Write header to file, followed by XML */
     if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
@@ -3991,7 +4011,7 @@ static int qemudDomainSave(virDomainPtr
     if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
         const char *args[] = { "cat", NULL };
         qemuDomainObjEnterMonitorWithDriver(driver, vm);
-        rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+        rc = qemuMonitorMigrateToFile(priv->mon, 0, args, path, offset);
         qemuDomainObjExitMonitorWithDriver(driver, vm);
     } else {
         const char *prog = qemudSaveCompressionTypeToString(header.compressed);
@@ -4001,7 +4021,7 @@ static int qemudDomainSave(virDomainPtr
             NULL
         };
         qemuDomainObjEnterMonitorWithDriver(driver, vm);
-        rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+        rc = qemuMonitorMigrateToFile(priv->mon, 0, args, path, offset);
         qemuDomainObjExitMonitorWithDriver(driver, vm);
     }
 
@@ -4128,7 +4148,7 @@ static int qemudDomainCoreDump(virDomain
     }
 
     qemuDomainObjEnterMonitor(vm);
-    ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+    ret = qemuMonitorMigrateToFile(priv->mon, 0, args, path, 0);
     qemuDomainObjExitMonitor(vm);
     paused |= (ret == 0);
 
@@ -8069,7 +8089,7 @@ static int doTunnelMigrate(virDomainPtr
         internalret = qemuMonitorMigrateToUnix(priv->mon, 1, unixfile);
     else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
         const char *args[] = { "nc", "-U", unixfile, NULL };
-        internalret = qemuMonitorMigrateToCommand(priv->mon, 1, args, "/dev/null");
+        internalret = qemuMonitorMigrateToCommand(priv->mon, 1, args);
     } else {
         internalret = -1;
     }
Index: libvirt-0.7.6/src/qemu/qemu_monitor.c
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_monitor.c
+++ libvirt-0.7.6/src/qemu/qemu_monitor.c
@@ -1031,17 +1031,40 @@ int qemuMonitorMigrateToHost(qemuMonitor
 
 int qemuMonitorMigrateToCommand(qemuMonitorPtr mon,
                                 int background,
-                                const char * const *argv,
-                                const char *target)
+                                const char * const *argv)
 {
     int ret;
-    DEBUG("mon=%p, fd=%d argv=%p target=%s",
-          mon, mon->fd, argv, target);
+    DEBUG("mon=%p, fd=%d argv=%p",
+          mon, mon->fd, argv);
 
     if (mon->json)
-        ret = qemuMonitorJSONMigrateToCommand(mon, background, argv, target);
+        ret = qemuMonitorJSONMigrateToCommand(mon, background, argv);
     else
-        ret = qemuMonitorTextMigrateToCommand(mon, background, argv, target);
+        ret = qemuMonitorTextMigrateToCommand(mon, background, argv);
+    return ret;
+}
+
+int qemuMonitorMigrateToFile(qemuMonitorPtr mon,
+                             int background,
+                             const char * const *argv,
+                             const char *target,
+                             unsigned long long offset)
+{
+    int ret;
+    DEBUG("mon=%p, fd=%d argv=%p target=%s offset=%llu",
+          mon, mon->fd, argv, target, offset);
+
+    if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                        _("file offset must be a multiple of %llu"),
+                        QEMU_MONITOR_MIGRATE_TO_FILE_BS);
+        return -1;
+    }
+
+    if (mon->json)
+        ret = qemuMonitorJSONMigrateToFile(mon, background, argv, target, offset);
+    else
+        ret = qemuMonitorTextMigrateToFile(mon, background, argv, target, offset);
     return ret;
 }
 
Index: libvirt-0.7.6/src/qemu/qemu_monitor.h
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_monitor.h
+++ libvirt-0.7.6/src/qemu/qemu_monitor.h
@@ -197,8 +197,15 @@ int qemuMonitorMigrateToHost(qemuMonitor
 
 int qemuMonitorMigrateToCommand(qemuMonitorPtr mon,
                                 int background,
-                                const char * const *argv,
-                                const char *target);
+                                const char * const *argv);
+
+# define QEMU_MONITOR_MIGRATE_TO_FILE_BS 512llu
+
+int qemuMonitorMigrateToFile(qemuMonitorPtr mon,
+                             int background,
+                             const char * const *argv,
+                             const char *target,
+                             unsigned long long offset);
 
 int qemuMonitorMigrateToUnix(qemuMonitorPtr mon,
                              int background,
Index: libvirt-0.7.6/src/qemu/qemu_monitor_json.c
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_monitor_json.c
+++ libvirt-0.7.6/src/qemu/qemu_monitor_json.c
@@ -1144,8 +1144,36 @@ int qemuMonitorJSONMigrateToHost(qemuMon
 
 int qemuMonitorJSONMigrateToCommand(qemuMonitorPtr mon,
                                     int background,
-                                    const char * const *argv,
-                                    const char *target)
+                                    const char * const *argv)
+{
+    char *argstr;
+    char *dest = NULL;
+    int ret = -1;
+
+    argstr = virArgvToString(argv);
+    if (!argstr) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&dest, "exec:%s", argstr) < 0) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    ret = qemuMonitorJSONMigrate(mon, background, dest);
+
+cleanup:
+    VIR_FREE(argstr);
+    VIR_FREE(dest);
+    return ret;
+}
+
+int qemuMonitorJSONMigrateToFile(qemuMonitorPtr mon,
+                                 int background,
+                                 const char * const *argv,
+                                 const char *target,
+                                 unsigned long long offset)
 {
     char *argstr;
     char *dest = NULL;
@@ -1165,7 +1193,10 @@ int qemuMonitorJSONMigrateToCommand(qemu
         goto cleanup;
     }
 
-    if (virAsprintf(&dest, "exec:%s >>%s 2>/dev/null", argstr, safe_target) < 0) {
+    if (virAsprintf(&dest, "exec:%s | dd of=%s bs=%llu seek=%llu",
+                    argstr, safe_target,
+                    QEMU_MONITOR_MIGRATE_TO_FILE_BS,
+                    offset / QEMU_MONITOR_MIGRATE_TO_FILE_BS) < 0) {
         virReportOOMError(NULL);
         goto cleanup;
     }
Index: libvirt-0.7.6/src/qemu/qemu_monitor_json.h
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_monitor_json.h
+++ libvirt-0.7.6/src/qemu/qemu_monitor_json.h
@@ -91,8 +91,13 @@ int qemuMonitorJSONMigrateToHost(qemuMon
 
 int qemuMonitorJSONMigrateToCommand(qemuMonitorPtr mon,
                                     int background,
-                                    const char * const *argv,
-                                    const char *target);
+                                    const char * const *argv);
+
+int qemuMonitorJSONMigrateToFile(qemuMonitorPtr mon,
+                                 int background,
+                                 const char * const *argv,
+                                 const char *target,
+                                 unsigned long long offset);
 
 int qemuMonitorJSONMigrateToUnix(qemuMonitorPtr mon,
                                  int background,
Index: libvirt-0.7.6/src/qemu/qemu_monitor_text.c
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_monitor_text.c
+++ libvirt-0.7.6/src/qemu/qemu_monitor_text.c
@@ -1130,8 +1130,36 @@ int qemuMonitorTextMigrateToHost(qemuMon
 
 int qemuMonitorTextMigrateToCommand(qemuMonitorPtr mon,
                                     int background,
-                                    const char * const *argv,
-                                    const char *target)
+                                    const char * const *argv)
+{
+    char *argstr;
+    char *dest = NULL;
+    int ret = -1;
+
+    argstr = virArgvToString(argv);
+    if (!argstr) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&dest, "exec:%s", argstr) < 0) {
+        virReportOOMError(NULL);
+        goto cleanup;
+    }
+
+    ret = qemuMonitorTextMigrate(mon, background, dest);
+
+cleanup:
+    VIR_FREE(argstr);
+    VIR_FREE(dest);
+    return ret;
+}
+
+int qemuMonitorTextMigrateToFile(qemuMonitorPtr mon,
+                                 int background,
+                                 const char * const *argv,
+                                 const char *target,
+                                 unsigned long long offset)
 {
     char *argstr;
     char *dest = NULL;
@@ -1151,7 +1179,10 @@ int qemuMonitorTextMigrateToCommand(qemu
         goto cleanup;
     }
 
-    if (virAsprintf(&dest, "exec:%s >>%s 2>/dev/null", argstr, safe_target) < 0) {
+    if (virAsprintf(&dest, "exec:%s | dd of=%s bs=%llu seek=%llu",
+                    argstr, safe_target,
+                    QEMU_MONITOR_MIGRATE_TO_FILE_BS,
+                    offset / QEMU_MONITOR_MIGRATE_TO_FILE_BS) < 0) {
         virReportOOMError(NULL);
         goto cleanup;
     }
Index: libvirt-0.7.6/src/qemu/qemu_monitor_text.h
===================================================================
--- libvirt-0.7.6.orig/src/qemu/qemu_monitor_text.h
+++ libvirt-0.7.6/src/qemu/qemu_monitor_text.h
@@ -95,8 +95,13 @@ int qemuMonitorTextMigrateToHost(qemuMon
 
 int qemuMonitorTextMigrateToCommand(qemuMonitorPtr mon,
                                     int background,
-                                    const char * const *argv,
-                                    const char *target);
+                                    const char * const *argv);
+
+int qemuMonitorTextMigrateToFile(qemuMonitorPtr mon,
+                                 int background,
+                                 const char * const *argv,
+                                 const char *target,
+                                 unsigned long long offset);
 
 int qemuMonitorTextMigrateToUnix(qemuMonitorPtr mon,
                                  int background,
