99cbc7
From 539a83390fb4b4b0dd7b029b7dd4ba2a345611cd Mon Sep 17 00:00:00 2001
99cbc7
Message-Id: <539a83390fb4b4b0dd7b029b7dd4ba2a345611cd@dist-git>
99cbc7
From: Jiri Denemark <jdenemar@redhat.com>
99cbc7
Date: Tue, 4 Jun 2019 13:04:33 +0200
99cbc7
Subject: [PATCH] qemu: Check TSC frequency before starting QEMU
99cbc7
MIME-Version: 1.0
99cbc7
Content-Type: text/plain; charset=UTF-8
99cbc7
Content-Transfer-Encoding: 8bit
99cbc7
99cbc7
When migrating a domain with invtsc CPU feature enabled, the TSC
99cbc7
frequency of the destination host must match the frequency used when the
99cbc7
domain was started on the source host or the destination host has to
99cbc7
support TSC scaling.
99cbc7
99cbc7
If the frequencies do not match and the destination host does not
99cbc7
support TSC scaling, QEMU will fail to set the right TSC frequency when
99cbc7
starting vCPUs on the destination and thus migration will fail. However,
99cbc7
this is quite late since both host might have spent significant time
99cbc7
transferring memory and perhaps even storage data.
99cbc7
99cbc7
By adding the check to libvirt we can let migration fail before any data
99cbc7
starts to be sent over. If for some reason libvirt is unable to detect
99cbc7
the host's TSC frequency or scaling support, we'll just let QEMU try and
99cbc7
the migration will either succeed or fail later.
99cbc7
99cbc7
Luckily, we mandate TSC frequency to be explicitly set in the domain XML
99cbc7
to even allow migration of domains with invtsc. We can just check
99cbc7
whether the requested frequency is compatible with the current host
99cbc7
before starting QEMU.
99cbc7
99cbc7
https://bugzilla.redhat.com/show_bug.cgi?id=1641702
99cbc7
99cbc7
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
99cbc7
(cherry picked from commit 7da62c91f043209e3d40c2dc7655c5e35a4309bf)
99cbc7
99cbc7
Conflicts:
99cbc7
	src/qemu/qemu_process.c
99cbc7
            - qemuProcessStartValidateXML function was removed upstream
99cbc7
              by commit v4.9.0-89-g91afd53cb8
99cbc7
99cbc7
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
99cbc7
Message-Id: <f5fcbf9d5afc4e156d1d2c888dc360d06bb29a1a.1559646067.git.jdenemar@redhat.com>
99cbc7
Reviewed-by: Ján Tomko <jtomko@redhat.com>
99cbc7
---
99cbc7
 src/qemu/qemu_process.c | 53 +++++++++++++++++++++++++++++++++++++++++
99cbc7
 1 file changed, 53 insertions(+)
99cbc7
99cbc7
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
99cbc7
index 2795796166..7f70d79566 100644
99cbc7
--- a/src/qemu/qemu_process.c
99cbc7
+++ b/src/qemu/qemu_process.c
99cbc7
@@ -5181,6 +5181,56 @@ qemuProcessStartValidateXML(virQEMUDriverPtr driver,
99cbc7
 }
99cbc7
 
99cbc7
 
99cbc7
+static int
99cbc7
+qemuProcessStartValidateTSC(virDomainObjPtr vm,
99cbc7
+                            virCapsPtr caps)
99cbc7
+{
99cbc7
+    size_t i;
99cbc7
+    unsigned long long freq = 0;
99cbc7
+    virHostCPUTscInfoPtr tsc;
99cbc7
+
99cbc7
+    for (i = 0; i < vm->def->clock.ntimers; i++) {
99cbc7
+        virDomainTimerDefPtr timer = vm->def->clock.timers[i];
99cbc7
+
99cbc7
+        if (timer->name == VIR_DOMAIN_TIMER_NAME_TSC &&
99cbc7
+            timer->frequency > 0) {
99cbc7
+            freq = timer->frequency;
99cbc7
+            break;
99cbc7
+        }
99cbc7
+    }
99cbc7
+
99cbc7
+    if (freq == 0)
99cbc7
+        return 0;
99cbc7
+
99cbc7
+    VIR_DEBUG("Requested TSC frequency %llu Hz", freq);
99cbc7
+
99cbc7
+    if (!caps->host.cpu || !caps->host.cpu->tsc) {
99cbc7
+        VIR_DEBUG("Host TSC frequency could not be probed");
99cbc7
+        return 0;
99cbc7
+    }
99cbc7
+
99cbc7
+    tsc = caps->host.cpu->tsc;
99cbc7
+    VIR_DEBUG("Host TSC frequency %llu Hz, scaling %s",
99cbc7
+              tsc->frequency, virTristateBoolTypeToString(tsc->scaling));
99cbc7
+
99cbc7
+    if (freq == tsc->frequency || tsc->scaling == VIR_TRISTATE_BOOL_YES)
99cbc7
+        return 0;
99cbc7
+
99cbc7
+    if (tsc->scaling == VIR_TRISTATE_BOOL_ABSENT) {
99cbc7
+        VIR_DEBUG("TSC frequencies do not match and scaling support is "
99cbc7
+                  "unknown, QEMU will try and possibly fail later");
99cbc7
+        return 0;
99cbc7
+    }
99cbc7
+
99cbc7
+    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
99cbc7
+                   _("Requested TSC frequency %llu Hz does not match "
99cbc7
+                     "host (%llu Hz) and TSC scaling is not supported "
99cbc7
+                     "by the host CPU"),
99cbc7
+                   freq, tsc->frequency);
99cbc7
+    return -1;
99cbc7
+}
99cbc7
+
99cbc7
+
99cbc7
 /**
99cbc7
  * qemuProcessStartValidate:
99cbc7
  * @vm: domain object
99cbc7
@@ -5241,6 +5291,9 @@ qemuProcessStartValidate(virQEMUDriverPtr driver,
99cbc7
     if (qemuProcessStartValidateDisks(vm, qemuCaps) < 0)
99cbc7
         return -1;
99cbc7
 
99cbc7
+    if (qemuProcessStartValidateTSC(vm, caps) < 0)
99cbc7
+        return -1;
99cbc7
+
99cbc7
     VIR_DEBUG("Checking for any possible (non-fatal) issues");
99cbc7
 
99cbc7
     qemuProcessStartWarnShmem(vm);
99cbc7
-- 
99cbc7
2.21.0
99cbc7