diff mbox

[kvm-unit-tests] x86: hyperv_stimer: add test for busy message slot

Message ID 20170720154250.5683-1-rkagan@virtuozzo.com (mailing list archive)
State New, archived
Headers show

Commit Message

Roman Kagan July 20, 2017, 3:42 p.m. UTC
When a SynIC timer expires it attempts to deliver a message to the
corresponding slot, which may be busy (e.g. because the guest hasn't yet
processed the previous message).

KVM used to livelock here, endlessly retrying message delivery without
letting the guest to run and release the slot (a patch fixing that has
been posted to KVM ml).

Add a testcase for this scenario.

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
---
 x86/hyperv_stimer.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
diff mbox

Patch

diff --git a/x86/hyperv_stimer.c b/x86/hyperv_stimer.c
index 9fcb0f3..bd7f966 100644
--- a/x86/hyperv_stimer.c
+++ b/x86/hyperv_stimer.c
@@ -271,6 +271,35 @@  static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer)
     stimer_shutdown(timer);
 }
 
+static void stimer_test_one_shot_busy(int vcpu, struct stimer *timer)
+{
+    struct hv_message_page *msg_page = g_synic_vcpu[vcpu].msg_page;
+    struct hv_message *msg = &msg_page->sint_message[timer->sint];
+
+    msg->header.message_type = HVMSG_TIMER_EXPIRED;
+    wmb();
+
+    stimer_start(timer, false, false, ONE_MS_IN_100NS, SINT1_NUM);
+
+    do
+        rmb();
+    while (!msg->header.message_flags.msg_pending);
+
+    report("no timer fired while msg slot busy: vcpu %d",
+           !atomic_read(&timer->fire_count), vcpu);
+
+    msg->header.message_type = HVMSG_NONE;
+    wmb();
+    wrmsr(HV_X64_MSR_EOM, 0);
+
+    while (atomic_read(&timer->fire_count) < 1) {
+        pause();
+    }
+    report("timer resumed when msg slot released: vcpu %d", true, vcpu);
+
+    stimer_shutdown(timer);
+}
+
 static void stimer_test(void *ctx)
 {
     int vcpu = smp_id();
@@ -286,6 +315,7 @@  static void stimer_test(void *ctx)
     stimer_test_one_shot(vcpu, timer1);
     stimer_test_auto_enable_one_shot(vcpu, timer2);
     stimer_test_auto_enable_periodic(vcpu, timer1);
+    stimer_test_one_shot_busy(vcpu, timer1);
 
     irq_disable();
 }