[PATCH 1/3] Sync guest viewable TSC when vcpu migrated

Leonard Norrgard
2007-03-02T16:48:38Z

[-- Attachment #1: Type: text/plain, Size: 508 bytes --]

When a vcpu is migrated to another cpu, an unexpected difference in
current and previous cpu TSC values can cause a guest to wait
indefinitely. A known workaround has been to run kvm with taskset,
locking it to a single cpu. This patch modifies the guest viewable TSC
so that the TSC is guaranteed to be monotonically increasing.

Thanks to Avi Kivity for help in pinpointing this issue and advice for
fixing it.

Signed-off-by: Leonard Norrgård <vinsci-g2GXA8XeJSExHbG02/KK1g@public.gmane.org>

[-- Attachment #2: 01_sync_tsc_when_vcpu_migrated.patch --]
[-- Type: text/x-diff, Size: 2286 bytes --]

Index: linux-2.6/drivers/kvm/svm.c
===================================================================
--- linux-2.6.orig/drivers/kvm/svm.c 2007-03-02 17:29:57.000000000 +0200
+++ linux-2.6/drivers/kvm/svm.c 2007-03-02 17:31:15.000000000 +0200
@@ -598,9 +598,45 @@
kfree(vcpu->svm);
}

+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+ u64 *tsc = arg;
+ rdtscll(*tsc);
+}
+#endif
+
+/*
+ * Switches to specified vcpu, until a matching vcpu_put(), but assumes
+ * vcpu mutex is already taken.
+ */
static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu)
{
- get_cpu();
+ int cpu;
+
+ cpu = get_cpu();
+
+#ifdef CONFIG_SMP
+ if (vcpu->cpu != cpu) {
+ if (vcpu->cpu != -1) {
+ u64 tsc_this, tsc_previous;
+
+ /* Get TSC value for this and the previous cpu. */
+ rdtscll(tsc_this);
+ smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+ &tsc_previous, 0, 1);
+
+ /*
+ * Make sure that the guest sees a monotonically
+ * increasing TSC.
+ */
+ vcpu->svm->vmcb->control.tsc_offset +=
+ tsc_previous - tsc_this;
+ }
+ }
+#endif
+
+ vcpu->cpu = cpu;
return vcpu;
}

Index: linux-2.6/drivers/kvm/vmx.c
===================================================================
--- linux-2.6.orig/drivers/kvm/vmx.c 2007-03-02 17:30:01.000000000 +0200
+++ linux-2.6/drivers/kvm/vmx.c 2007-03-02 17:30:17.000000000 +0200
@@ -200,6 +200,14 @@
#endif
}

+#ifdef CONFIG_SMP
+static void ipi_rdtscll(void *arg)
+{
+ u64 *tsc = arg;
+ rdtscll(*tsc);
+}
+#endif
+
/*
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.
@@ -230,6 +238,25 @@
struct descriptor_table dt;
unsigned long sysenter_esp;

+#ifdef CONFIG_SMP
+ if (vcpu->cpu != -1) {
+ u64 tsc_this, tsc_previous, guest_tsc_offset;
+
+ /* Get TSC value for this and the previous cpu. */
+ rdtscll(tsc_this);
+ smp_call_function_single(vcpu->cpu, ipi_rdtscll,
+ &tsc_previous, 0, 1);
+
+ /*
+ * Make sure that the guest sees a monotonically
+ * increasing TSC.
+ */
+ guest_tsc_offset = vmcs_read64(TSC_OFFSET);
+ vmcs_write64(TSC_OFFSET, guest_tsc_offset +
+ tsc_previous - tsc_this);
+ }
+#endif
+
vcpu->cpu = cpu;
/*
* Linux uses per-cpu TSS and GDT, so set these when switching

[-- Attachment #3: Type: text/plain, Size: 345 bytes --]

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org