Blame SOURCES/kvm-vhost-user-support-registering-external-host-notifie.patch

1bdc94
From 3a5f44900a64ea2bdf809f1a8df8a4a255dbe014 Mon Sep 17 00:00:00 2001
1bdc94
From: "plai@redhat.com" <plai@redhat.com>
1bdc94
Date: Thu, 21 Jun 2018 18:54:44 +0200
1bdc94
Subject: [PATCH 35/57] vhost-user: support registering external host notifiers
1bdc94
1bdc94
RH-Author: plai@redhat.com
1bdc94
Message-id: <1529607285-9942-10-git-send-email-plai@redhat.com>
1bdc94
Patchwork-id: 80940
1bdc94
O-Subject: [RHEL7.6 PATCH BZ 1526645 09/10] vhost-user: support registering external host notifiers
1bdc94
Bugzilla: 1526645
1bdc94
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
1bdc94
RH-Acked-by: Maxime Coquelin <maxime.coquelin@redhat.com>
1bdc94
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
1bdc94
1bdc94
From: Tiwei Bie <tiwei.bie@intel.com>
1bdc94
1bdc94
This patch introduces VHOST_USER_PROTOCOL_F_HOST_NOTIFIER.
1bdc94
With this feature negotiated, vhost-user backend can register
1bdc94
memory region based host notifiers. And it will allow the guest
1bdc94
driver in the VM to notify the hardware accelerator at the
1bdc94
vhost-user backend directly.
1bdc94
1bdc94
Signed-off-by: Tiwei Bie <tiwei.bie@intel.com>
1bdc94
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
1bdc94
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1bdc94
(cherry picked from commit 44866521bd6ea8e5152a87664dea1eee90c9438b)
1bdc94
Signed-off-by: Paul Lai <plai@redhat.com>
1bdc94
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
1bdc94
---
1bdc94
 docs/interop/vhost-user.txt    |  33 ++++++++++++
1bdc94
 hw/virtio/vhost-user.c         | 113 +++++++++++++++++++++++++++++++++++++++++
1bdc94
 include/hw/virtio/vhost-user.h |   8 +++
1bdc94
 3 files changed, 154 insertions(+)
1bdc94
1bdc94
diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt
1bdc94
index 682a683..d51fd58 100644
1bdc94
--- a/docs/interop/vhost-user.txt
1bdc94
+++ b/docs/interop/vhost-user.txt
1bdc94
@@ -132,6 +132,16 @@ Depending on the request type, payload can be:
1bdc94
    Payload: Size bytes array holding the contents of the virtio
1bdc94
        device's configuration space
1bdc94
 
1bdc94
+ * Vring area description
1bdc94
+   -----------------------
1bdc94
+   | u64 | size | offset |
1bdc94
+   -----------------------
1bdc94
+
1bdc94
+   u64: a 64-bit integer contains vring index and flags
1bdc94
+   Size: a 64-bit size of this area
1bdc94
+   Offset: a 64-bit offset of this area from the start of the
1bdc94
+       supplied file descriptor
1bdc94
+
1bdc94
 In QEMU the vhost-user message is implemented with the following struct:
1bdc94
 
1bdc94
 typedef struct VhostUserMsg {
1bdc94
@@ -146,6 +156,7 @@ typedef struct VhostUserMsg {
1bdc94
         VhostUserLog log;
1bdc94
         struct vhost_iotlb_msg iotlb;
1bdc94
         VhostUserConfig config;
1bdc94
+        VhostUserVringArea area;
1bdc94
     };
1bdc94
 } QEMU_PACKED VhostUserMsg;
1bdc94
 
1bdc94
@@ -385,6 +396,7 @@ Protocol features
1bdc94
 #define VHOST_USER_PROTOCOL_F_PAGEFAULT      8
1bdc94
 #define VHOST_USER_PROTOCOL_F_CONFIG         9
1bdc94
 #define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD  10
1bdc94
+#define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER  11
1bdc94
 
1bdc94
 Master message types
1bdc94
 --------------------
1bdc94
@@ -782,6 +794,27 @@ Slave message types
1bdc94
      the VHOST_USER_NEED_REPLY flag, master must respond with zero when
1bdc94
      operation is successfully completed, or non-zero otherwise.
1bdc94
 
1bdc94
+ * VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG
1bdc94
+
1bdc94
+      Id: 3
1bdc94
+      Equivalent ioctl: N/A
1bdc94
+      Slave payload: vring area description
1bdc94
+      Master payload: N/A
1bdc94
+
1bdc94
+      Sets host notifier for a specified queue. The queue index is contained
1bdc94
+      in the u64 field of the vring area description. The host notifier is
1bdc94
+      described by the file descriptor (typically it's a VFIO device fd) which
1bdc94
+      is passed as ancillary data and the size (which is mmap size and should
1bdc94
+      be the same as host page size) and offset (which is mmap offset) carried
1bdc94
+      in the vring area description. QEMU can mmap the file descriptor based
1bdc94
+      on the size and offset to get a memory range. Registering a host notifier
1bdc94
+      means mapping this memory range to the VM as the specified queue's notify
1bdc94
+      MMIO region. Slave sends this request to tell QEMU to de-register the
1bdc94
+      existing notifier if any and register the new notifier if the request is
1bdc94
+      sent with a file descriptor.
1bdc94
+      This request should be sent only when VHOST_USER_PROTOCOL_F_HOST_NOTIFIER
1bdc94
+      protocol feature has been successfully negotiated.
1bdc94
+
1bdc94
 VHOST_USER_PROTOCOL_F_REPLY_ACK:
1bdc94
 -------------------------------
1bdc94
 The original vhost-user specification only demands replies for certain
1bdc94
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
1bdc94
index a715c5c..c30fc3d 100644
1bdc94
--- a/hw/virtio/vhost-user.c
1bdc94
+++ b/hw/virtio/vhost-user.c
1bdc94
@@ -13,6 +13,7 @@
1bdc94
 #include "hw/virtio/vhost.h"
1bdc94
 #include "hw/virtio/vhost-user.h"
1bdc94
 #include "hw/virtio/vhost-backend.h"
1bdc94
+#include "hw/virtio/virtio.h"
1bdc94
 #include "hw/virtio/virtio-net.h"
1bdc94
 #include "chardev/char-fe.h"
1bdc94
 #include "sysemu/kvm.h"
1bdc94
@@ -50,6 +51,7 @@ enum VhostUserProtocolFeature {
1bdc94
     VHOST_USER_PROTOCOL_F_PAGEFAULT = 8,
1bdc94
     VHOST_USER_PROTOCOL_F_CONFIG = 9,
1bdc94
     VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD = 10,
1bdc94
+    VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
1bdc94
     VHOST_USER_PROTOCOL_F_MAX
1bdc94
 };
1bdc94
 
1bdc94
@@ -94,6 +96,7 @@ typedef enum VhostUserSlaveRequest {
1bdc94
     VHOST_USER_SLAVE_NONE = 0,
1bdc94
     VHOST_USER_SLAVE_IOTLB_MSG = 1,
1bdc94
     VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2,
1bdc94
+    VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3,
1bdc94
     VHOST_USER_SLAVE_MAX
1bdc94
 }  VhostUserSlaveRequest;
1bdc94
 
1bdc94
@@ -138,6 +141,12 @@ static VhostUserConfig c __attribute__ ((unused));
1bdc94
                                    + sizeof(c.size) \
1bdc94
                                    + sizeof(c.flags))
1bdc94
 
1bdc94
+typedef struct VhostUserVringArea {
1bdc94
+    uint64_t u64;
1bdc94
+    uint64_t size;
1bdc94
+    uint64_t offset;
1bdc94
+} VhostUserVringArea;
1bdc94
+
1bdc94
 typedef struct {
1bdc94
     VhostUserRequest request;
1bdc94
 
1bdc94
@@ -159,6 +168,7 @@ typedef union {
1bdc94
         struct vhost_iotlb_msg iotlb;
1bdc94
         VhostUserConfig config;
1bdc94
         VhostUserCryptoSession session;
1bdc94
+        VhostUserVringArea area;
1bdc94
 } VhostUserPayload;
1bdc94
 
1bdc94
 typedef struct VhostUserMsg {
1bdc94
@@ -640,9 +650,37 @@ static int vhost_user_set_vring_num(struct vhost_dev *dev,
1bdc94
     return vhost_set_vring(dev, VHOST_USER_SET_VRING_NUM, ring);
1bdc94
 }
1bdc94
 
1bdc94
+static void vhost_user_host_notifier_restore(struct vhost_dev *dev,
1bdc94
+                                             int queue_idx)
1bdc94
+{
1bdc94
+    struct vhost_user *u = dev->opaque;
1bdc94
+    VhostUserHostNotifier *n = &u->user->notifier[queue_idx];
1bdc94
+    VirtIODevice *vdev = dev->vdev;
1bdc94
+
1bdc94
+    if (n->addr && !n->set) {
1bdc94
+        virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true);
1bdc94
+        n->set = true;
1bdc94
+    }
1bdc94
+}
1bdc94
+
1bdc94
+static void vhost_user_host_notifier_remove(struct vhost_dev *dev,
1bdc94
+                                            int queue_idx)
1bdc94
+{
1bdc94
+    struct vhost_user *u = dev->opaque;
1bdc94
+    VhostUserHostNotifier *n = &u->user->notifier[queue_idx];
1bdc94
+    VirtIODevice *vdev = dev->vdev;
1bdc94
+
1bdc94
+    if (n->addr && n->set) {
1bdc94
+        virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
1bdc94
+        n->set = false;
1bdc94
+    }
1bdc94
+}
1bdc94
+
1bdc94
 static int vhost_user_set_vring_base(struct vhost_dev *dev,
1bdc94
                                      struct vhost_vring_state *ring)
1bdc94
 {
1bdc94
+    vhost_user_host_notifier_restore(dev, ring->index);
1bdc94
+
1bdc94
     return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring);
1bdc94
 }
1bdc94
 
1bdc94
@@ -676,6 +714,8 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
1bdc94
         .hdr.size = sizeof(msg.payload.state),
1bdc94
     };
1bdc94
 
1bdc94
+    vhost_user_host_notifier_remove(dev, ring->index);
1bdc94
+
1bdc94
     if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
1bdc94
         return -1;
1bdc94
     }
1bdc94
@@ -849,6 +889,66 @@ static int vhost_user_slave_handle_config_change(struct vhost_dev *dev)
1bdc94
     return ret;
1bdc94
 }
1bdc94
 
1bdc94
+static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
1bdc94
+                                                       VhostUserVringArea *area,
1bdc94
+                                                       int fd)
1bdc94
+{
1bdc94
+    int queue_idx = area->u64 & VHOST_USER_VRING_IDX_MASK;
1bdc94
+    size_t page_size = qemu_real_host_page_size;
1bdc94
+    struct vhost_user *u = dev->opaque;
1bdc94
+    VhostUserState *user = u->user;
1bdc94
+    VirtIODevice *vdev = dev->vdev;
1bdc94
+    VhostUserHostNotifier *n;
1bdc94
+    void *addr;
1bdc94
+    char *name;
1bdc94
+
1bdc94
+    if (!virtio_has_feature(dev->protocol_features,
1bdc94
+                            VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) ||
1bdc94
+        vdev == NULL || queue_idx >= virtio_get_num_queues(vdev)) {
1bdc94
+        return -1;
1bdc94
+    }
1bdc94
+
1bdc94
+    n = &user->notifier[queue_idx];
1bdc94
+
1bdc94
+    if (n->addr) {
1bdc94
+        virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, false);
1bdc94
+        object_unparent(OBJECT(&n->mr));
1bdc94
+        munmap(n->addr, page_size);
1bdc94
+        n->addr = NULL;
1bdc94
+    }
1bdc94
+
1bdc94
+    if (area->u64 & VHOST_USER_VRING_NOFD_MASK) {
1bdc94
+        return 0;
1bdc94
+    }
1bdc94
+
1bdc94
+    /* Sanity check. */
1bdc94
+    if (area->size != page_size) {
1bdc94
+        return -1;
1bdc94
+    }
1bdc94
+
1bdc94
+    addr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
1bdc94
+                fd, area->offset);
1bdc94
+    if (addr == MAP_FAILED) {
1bdc94
+        return -1;
1bdc94
+    }
1bdc94
+
1bdc94
+    name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]",
1bdc94
+                           user, queue_idx);
1bdc94
+    memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
1bdc94
+                                      page_size, addr);
1bdc94
+    g_free(name);
1bdc94
+
1bdc94
+    if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) {
1bdc94
+        munmap(addr, page_size);
1bdc94
+        return -1;
1bdc94
+    }
1bdc94
+
1bdc94
+    n->addr = addr;
1bdc94
+    n->set = true;
1bdc94
+
1bdc94
+    return 0;
1bdc94
+}
1bdc94
+
1bdc94
 static void slave_read(void *opaque)
1bdc94
 {
1bdc94
     struct vhost_dev *dev = opaque;
1bdc94
@@ -917,6 +1017,10 @@ static void slave_read(void *opaque)
1bdc94
     case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG :
1bdc94
         ret = vhost_user_slave_handle_config_change(dev);
1bdc94
         break;
1bdc94
+    case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG:
1bdc94
+        ret = vhost_user_slave_handle_vring_host_notifier(dev, &payload.area,
1bdc94
+                                                          fd[0]);
1bdc94
+        break;
1bdc94
     default:
1bdc94
         error_report("Received unexpected msg type.");
1bdc94
         ret = -EINVAL;
1bdc94
@@ -1648,6 +1752,15 @@ VhostUserState *vhost_user_init(void)
1bdc94
 
1bdc94
 void vhost_user_cleanup(VhostUserState *user)
1bdc94
 {
1bdc94
+    int i;
1bdc94
+
1bdc94
+    for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
1bdc94
+        if (user->notifier[i].addr) {
1bdc94
+            object_unparent(OBJECT(&user->notifier[i].mr));
1bdc94
+            munmap(user->notifier[i].addr, qemu_real_host_page_size);
1bdc94
+            user->notifier[i].addr = NULL;
1bdc94
+        }
1bdc94
+    }
1bdc94
 }
1bdc94
 
1bdc94
 const VhostOps user_ops = {
1bdc94
diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
1bdc94
index eb8bc0d..fd66039 100644
1bdc94
--- a/include/hw/virtio/vhost-user.h
1bdc94
+++ b/include/hw/virtio/vhost-user.h
1bdc94
@@ -9,9 +9,17 @@
1bdc94
 #define HW_VIRTIO_VHOST_USER_H
1bdc94
 
1bdc94
 #include "chardev/char-fe.h"
1bdc94
+#include "hw/virtio/virtio.h"
1bdc94
+
1bdc94
+typedef struct VhostUserHostNotifier {
1bdc94
+    MemoryRegion mr;
1bdc94
+    void *addr;
1bdc94
+    bool set;
1bdc94
+} VhostUserHostNotifier;
1bdc94
 
1bdc94
 typedef struct VhostUserState {
1bdc94
     CharBackend *chr;
1bdc94
+    VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX];
1bdc94
 } VhostUserState;
1bdc94
 
1bdc94
 VhostUserState *vhost_user_init(void);
1bdc94
-- 
1bdc94
1.8.3.1
1bdc94