qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Roman Kagan <rkagan@virtuozzo.com>
To: qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Eduardo Habkost <ehabkost@redhat.com>,
	Evgeny Yakovlev <eyakovlev@virtuozzo.com>,
	"Denis V . Lunev" <den@openvz.org>
Subject: [Qemu-devel] [PATCH 17/23] hyperv: add synic message delivery
Date: Tue,  6 Jun 2017 21:19:42 +0300	[thread overview]
Message-ID: <20170606181948.16238-18-rkagan@virtuozzo.com> (raw)
In-Reply-To: <20170606181948.16238-1-rkagan@virtuozzo.com>

Add infrastructure to deliver SynIC messages to the guest SynIC message
page.

Note that KVM also may want to deliver (SynIC timer) messages to the
same message slot.

The problem is that the access to a SynIC message slot is controlled by
the value of its .msg_type field which indicates if the slot is being
owned by the hypervisor (zero) or by the guest (non-zero).

This leaves no room for synchronizing multiple concurrent producers.

The simplest way to deal with this for both KVM and QEMU is to only
deliver messages in the vcpu thread.  KVM already does this; this patch
makes it for QEMU, too.

Specifically,

 - add a function for posting messages, which only copies the message
   into the staging buffer if its free, and schedules a work on the
   corresponding vcpu to actually deliver it to the guest slot;

 - instead of a sint ack callback, set up the sint route with a message
   status callback.  This function is called in a bh whenever there are
   updates to the message slot status: either the vcpu made definitive
   progress delivering the message from the staging buffer (succeeded or
   failed) or the guest issued EOM; the status is passed as an argument
   to the callback.

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
---
 target/i386/hyperv.h |   7 ++--
 target/i386/hyperv.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 109 insertions(+), 14 deletions(-)

diff --git a/target/i386/hyperv.h b/target/i386/hyperv.h
index 9dd5ca0..fa3e988 100644
--- a/target/i386/hyperv.h
+++ b/target/i386/hyperv.h
@@ -19,13 +19,12 @@
 #include "qemu/event_notifier.h"
 
 typedef struct HvSintRoute HvSintRoute;
-typedef void (*HvSintAckClb)(void *data);
+typedef void (*HvSintMsgCb)(void *data, int status);
 
 int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit);
 
 HvSintRoute *hyperv_sint_route_new(X86CPU *cpu, uint32_t sint,
-                                   HvSintAckClb sint_ack_clb,
-                                   void *sint_ack_clb_data);
+                                   HvSintMsgCb cb, void *cb_data);
 void hyperv_sint_route_ref(HvSintRoute *sint_route);
 void hyperv_sint_route_unref(HvSintRoute *sint_route);
 
@@ -38,4 +37,6 @@ void hyperv_synic_add(X86CPU *cpu);
 void hyperv_synic_reset(X86CPU *cpu);
 void hyperv_synic_update(X86CPU *cpu);
 
+int hyperv_post_msg(HvSintRoute *sint_route, struct hyperv_message *msg);
+
 #endif
diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c
index 165133a..0a7f9b1 100644
--- a/target/i386/hyperv.c
+++ b/target/i386/hyperv.c
@@ -44,8 +44,21 @@ struct HvSintRoute {
     int gsi;
     EventNotifier sint_set_notifier;
     EventNotifier sint_ack_notifier;
-    HvSintAckClb sint_ack_clb;
-    void *sint_ack_clb_data;
+
+    HvSintMsgCb msg_cb;
+    void *msg_cb_data;
+    QEMUBH *msg_bh;
+    struct hyperv_message *msg;
+    /*
+     * the state of the message staged in .msg:
+     * 0        - the staging area is not in use (after init or message
+     *            successfully delivered to guest)
+     * -EBUSY   - the staging area is being used in vcpu thread
+     * -EAGAIN  - delivery attempt failed due to slot being busy, retry
+     * -EXXXX   - error
+     */
+    int msg_status;
+
     unsigned refcount;
 };
 
@@ -112,6 +125,69 @@ static void synic_update(SynICState *synic)
     synic_update_evt_page_addr(synic);
 }
 
+/*
+ * Worker to transfer the message from the staging area into the guest-owned
+ * message page in vcpu context, which guarantees serialization with both KVM
+ * vcpu and the guest cpu.
+ */
+static void cpu_post_msg(CPUState *cs, run_on_cpu_data data)
+{
+    int ret;
+    HvSintRoute *sint_route = data.host_ptr;
+    SynICState *synic = sint_route->synic;
+    struct hyperv_message *dst_msg;
+
+    if (!synic->enabled || !synic->msg_page_addr) {
+        ret = -ENXIO;
+        goto notify;
+    }
+
+    dst_msg = &synic->msg_page->slot[sint_route->sint];
+
+    if (dst_msg->header.message_type != HV_MESSAGE_NONE) {
+        dst_msg->header.message_flags |= HV_MESSAGE_FLAG_PENDING;
+        ret = -EAGAIN;
+    } else {
+        memcpy(dst_msg, sint_route->msg, sizeof(*dst_msg));
+        ret = kvm_hv_sint_route_set_sint(sint_route);
+    }
+
+    memory_region_set_dirty(&synic->msg_page_mr, 0, sizeof(*synic->msg_page));
+
+notify:
+    sint_route->msg_status = ret;
+    /* notify the msg originator of the progress made; if the slot was busy we
+     * set msg_pending flag in it so it will be the guest who will do EOM and
+     * trigger the notification from KVM via sint_ack_notifier */
+    if (ret != -EAGAIN) {
+        qemu_bh_schedule(sint_route->msg_bh);
+    }
+}
+
+/*
+ * Post a Hyper-V message to the staging area, for delivery to guest in the
+ * vcpu thread.
+ */
+int hyperv_post_msg(HvSintRoute *sint_route, struct hyperv_message *src_msg)
+{
+    int ret = sint_route->msg_status;
+
+    assert(sint_route->msg_cb);
+
+    if (ret == -EBUSY) {
+        return -EAGAIN;
+    }
+    if (ret) {
+        return ret;
+    }
+
+    sint_route->msg_status = -EBUSY;
+    memcpy(sint_route->msg, src_msg, sizeof(*src_msg));
+
+    async_run_on_cpu(CPU(sint_route->synic->cpu), cpu_post_msg,
+                     RUN_ON_CPU_HOST_PTR(sint_route));
+    return 0;
+}
 
 static void async_synic_update(CPUState *cs, run_on_cpu_data data)
 {
@@ -164,17 +240,27 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
     }
 }
 
-static void kvm_hv_sint_ack_handler(EventNotifier *notifier)
+static void sint_ack_handler(EventNotifier *notifier)
 {
     HvSintRoute *sint_route = container_of(notifier, HvSintRoute,
                                            sint_ack_notifier);
     event_notifier_test_and_clear(notifier);
-    sint_route->sint_ack_clb(sint_route->sint_ack_clb_data);
+
+    if (sint_route->msg_status == -EAGAIN) {
+        qemu_bh_schedule(sint_route->msg_bh);
+    }
+}
+
+static void sint_msg_bh(void *opaque)
+{
+    HvSintRoute *sint_route = opaque;
+    int status = sint_route->msg_status;
+    sint_route->msg_status = 0;
+    sint_route->msg_cb(sint_route->msg_cb_data, status);
 }
 
 HvSintRoute *hyperv_sint_route_new(X86CPU *cpu, uint32_t sint,
-                                   HvSintAckClb sint_ack_clb,
-                                   void *sint_ack_clb_data)
+                                   HvSintMsgCb cb, void *cb_data)
 {
     SynICState *synic;
     HvSintRoute *sint_route;
@@ -189,14 +275,18 @@ HvSintRoute *hyperv_sint_route_new(X86CPU *cpu, uint32_t sint,
         goto err;
     }
 
-    ack_notifier = sint_ack_clb ? &sint_route->sint_ack_notifier : NULL;
+    ack_notifier = cb ? &sint_route->sint_ack_notifier : NULL;
     if (ack_notifier) {
+        sint_route->msg = g_new(struct hyperv_message, 1);
+
         r = event_notifier_init(ack_notifier, false);
         if (r) {
             goto err_sint_set_notifier;
         }
 
-        event_notifier_set_handler(ack_notifier, kvm_hv_sint_ack_handler);
+        event_notifier_set_handler(ack_notifier, sint_ack_handler);
+
+        sint_route->msg_bh = qemu_bh_new(sint_msg_bh, sint_route);
     }
 
     gsi = kvm_irqchip_add_hv_sint_route(kvm_state, hyperv_vp_index(cpu), sint);
@@ -211,8 +301,8 @@ HvSintRoute *hyperv_sint_route_new(X86CPU *cpu, uint32_t sint,
         goto err_irqfd;
     }
     sint_route->gsi = gsi;
-    sint_route->sint_ack_clb = sint_ack_clb;
-    sint_route->sint_ack_clb_data = sint_ack_clb_data;
+    sint_route->msg_cb = cb;
+    sint_route->msg_cb_data = cb_data;
     sint_route->synic = synic;
     sint_route->sint = sint;
     sint_route->refcount = 1;
@@ -223,8 +313,10 @@ err_irqfd:
     kvm_irqchip_release_virq(kvm_state, gsi);
 err_gsi:
     if (ack_notifier) {
+        qemu_bh_delete(sint_route->msg_bh);
         event_notifier_set_handler(ack_notifier, NULL);
         event_notifier_cleanup(ack_notifier);
+        g_free(sint_route->msg);
     }
 err_sint_set_notifier:
     event_notifier_cleanup(&sint_route->sint_set_notifier);
@@ -255,9 +347,11 @@ void hyperv_sint_route_unref(HvSintRoute *sint_route)
                                           &sint_route->sint_set_notifier,
                                           sint_route->gsi);
     kvm_irqchip_release_virq(kvm_state, sint_route->gsi);
-    if (sint_route->sint_ack_clb) {
+    if (sint_route->msg_cb) {
+        qemu_bh_delete(sint_route->msg_bh);
         event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
         event_notifier_cleanup(&sint_route->sint_ack_notifier);
+        g_free(sint_route->msg);
     }
     event_notifier_cleanup(&sint_route->sint_set_notifier);
     g_free(sint_route);
-- 
2.9.4

  parent reply	other threads:[~2017-06-06 18:20 UTC|newest]

Thread overview: 76+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-06 18:19 [Qemu-devel] [PATCH 00/23] hyperv fixes and enhancements Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 01/23] hyperv: add header with protocol definitions Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 02/23] update-linux-headers: prepare for hyperv.h removal Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 03/23] hyperv: set partition-wide MSRs only on first vcpu Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 04/23] hyperv: ensure msrs are inited properly Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 05/23] hyperv: ensure VP index equal to QEMU cpu_index Roman Kagan
2017-06-13 18:57   ` Eduardo Habkost
2017-06-14 11:25     ` Roman Kagan
2017-06-14 11:26       ` Paolo Bonzini
2017-06-14 13:00         ` Igor Mammedov
2017-06-15 12:41           ` Roman Kagan
2017-06-15 13:22             ` Paolo Bonzini
2017-06-15 13:27             ` Igor Mammedov
2017-06-15 16:05               ` Roman Kagan
2017-06-18 15:29                 ` Eduardo Habkost
2017-06-14 13:01         ` Eduardo Habkost
2017-06-14 13:11           ` Igor Mammedov
2017-06-14 13:17             ` Paolo Bonzini
2017-06-14 13:22               ` Eduardo Habkost
2017-06-14 13:37                 ` Paolo Bonzini
2017-06-14 13:38                 ` Igor Mammedov
2017-06-14 13:45                   ` Eduardo Habkost
2017-06-14 18:40                     ` Roman Kagan
2017-06-14 18:59                       ` Eduardo Habkost
2017-06-15  8:26                         ` Paolo Bonzini
2017-06-15 11:40                           ` Roman Kagan
2017-06-15 11:42                             ` Paolo Bonzini
2017-06-15 12:03                               ` Roman Kagan
2017-06-14 13:19             ` Eduardo Habkost
2017-06-14 13:00       ` Eduardo Habkost
2017-06-14 13:24         ` Igor Mammedov
2017-06-14 13:35           ` Eduardo Habkost
2017-06-14 15:31             ` Igor Mammedov
2017-06-06 18:19 ` [Qemu-devel] [PATCH 06/23] hyperv: helper to find vcpu by VP index Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 07/23] hyperv_testdev: refactor for readability Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 08/23] hyperv: cosmetic: g_malloc -> g_new Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 09/23] hyperv: synic: only setup ack notifier if there's a callback Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 10/23] hyperv: allow passing arbitrary data to sint ack callback Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 12/23] hyperv: make HvSintRoute reference-counted Roman Kagan
2017-06-14 13:53   ` Eduardo Habkost
2017-06-14 16:23     ` Roman Kagan
2017-06-23 12:44       ` Eduardo Habkost
2017-06-06 18:19 ` [Qemu-devel] [PATCH 13/23] hyperv: qdev-ify SynIC Roman Kagan
2017-06-13 18:34   ` Eduardo Habkost
2017-06-14  9:58     ` Roman Kagan
2017-06-14 12:46       ` Eduardo Habkost
2017-06-14 15:11         ` Roman Kagan
2017-06-14 15:21           ` Eduardo Habkost
2017-06-06 18:19 ` [Qemu-devel] [PATCH 14/23] kvm-all: make async_safe_run_on_cpu safe on kvm too Roman Kagan
2017-06-08 14:47   ` Paolo Bonzini
2017-06-06 18:19 ` [Qemu-devel] [PATCH 15/23] hyperv: make overlay pages for SynIC Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 16/23] hyperv: map overlay pages after updating msrs Roman Kagan
2017-06-14 11:12   ` Paolo Bonzini
2017-06-14 11:54     ` Roman Kagan
2017-06-14 12:11       ` Paolo Bonzini
2017-06-14 12:41         ` Roman Kagan
2017-06-14 12:46           ` Paolo Bonzini
2017-06-06 18:19 ` Roman Kagan [this message]
2017-06-14 15:08   ` [Qemu-devel] [PATCH 17/23] hyperv: add synic message delivery Paolo Bonzini
2017-06-14 15:28     ` Roman Kagan
2017-06-14 15:32       ` Paolo Bonzini
2017-06-14 15:39         ` Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 18/23] hyperv: add synic event flag signaling Roman Kagan
2017-06-14 15:07   ` Paolo Bonzini
2017-06-06 18:19 ` [Qemu-devel] [PATCH 19/23] hyperv: process SIGNAL_EVENT hypercall Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 20/23] hyperv: process POST_MESSAGE hypercall Roman Kagan
2017-06-14 11:19   ` Paolo Bonzini
2017-06-14 14:20     ` Roman Kagan
2017-06-14 14:30       ` Paolo Bonzini
2017-06-06 18:19 ` [Qemu-devel] [PATCH 21/23] hyperv_testdev: add SynIC message and event testmodes Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 22/23] MAINTAINERS: add myself and eyakovlev@ for hyperv* Roman Kagan
2017-06-06 18:19 ` [Qemu-devel] [PATCH 23/23] hyperv: update copyright notices Roman Kagan
     [not found] ` <20170606181948.16238-12-rkagan@virtuozzo.com>
2017-06-13 19:02   ` [Qemu-devel] [PATCH 11/23] hyperv: address HvSintRoute by X86CPU pointer Eduardo Habkost
2017-06-14 11:08     ` Paolo Bonzini
2017-06-14 12:14       ` Roman Kagan
2017-06-14 12:17         ` Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170606181948.16238-18-rkagan@virtuozzo.com \
    --to=rkagan@virtuozzo.com \
    --cc=den@openvz.org \
    --cc=ehabkost@redhat.com \
    --cc=eyakovlev@virtuozzo.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).