]> xenbits.xensource.com Git - qemu-xen.git/commitdiff
tap: vhost busy polling support
authorJason Wang <jasowang@redhat.com>
Wed, 6 Jul 2016 01:57:55 +0000 (09:57 +0800)
committerJason Wang <jasowang@redhat.com>
Thu, 7 Jul 2016 06:29:04 +0000 (14:29 +0800)
This patch add the capability of basic vhost net busy polling which is
supported by recent kernel. User could configure the maximum number of
us that could be spent on busy polling through a new property of tap
"poll-us".

Cc: Greg Kurz <groug@kaod.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
hw/net/vhost_net.c
hw/scsi/vhost-scsi.c
hw/virtio/vhost-backend.c
hw/virtio/vhost.c
include/hw/virtio/vhost-backend.h
include/hw/virtio/vhost.h
include/net/vhost_net.h
net/tap.c
net/vhost-user.c
qapi-schema.json
qemu-options.hx

index 50f4dcd655279c8e59acfe5e48c7cebca850ef9d..11fabc0b0a7e1c1886f3eafc468a0f5fe57c1612 100644 (file)
@@ -172,7 +172,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
     }
 
     r = vhost_dev_init(&net->dev, options->opaque,
-                       options->backend_type);
+                       options->backend_type, options->busyloop_timeout);
     if (r < 0) {
         goto fail;
     }
index 9261d51da799b39f5988b28643fd2f29496efb26..2a00f2f3c8b631eadc0e2adcafd2a143e43cf864 100644 (file)
@@ -248,7 +248,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
     s->dev.backend_features = 0;
 
     ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
-                         VHOST_BACKEND_TYPE_KERNEL);
+                         VHOST_BACKEND_TYPE_KERNEL, 0);
     if (ret < 0) {
         error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
                    strerror(-ret));
index b35890289f3bee7a2067188e902cceca9f98a4b1..d62372e5976e921ae9e49d51c03627d426a80e47 100644 (file)
@@ -138,6 +138,12 @@ static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
     return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
 }
 
+static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev,
+                                                   struct vhost_vring_state *s)
+{
+    return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s);
+}
+
 static int vhost_kernel_set_features(struct vhost_dev *dev,
                                      uint64_t features)
 {
@@ -185,6 +191,8 @@ static const VhostOps kernel_ops = {
         .vhost_get_vring_base = vhost_kernel_get_vring_base,
         .vhost_set_vring_kick = vhost_kernel_set_vring_kick,
         .vhost_set_vring_call = vhost_kernel_set_vring_call,
+        .vhost_set_vring_busyloop_timeout =
+                                vhost_kernel_set_vring_busyloop_timeout,
         .vhost_set_features = vhost_kernel_set_features,
         .vhost_get_features = vhost_kernel_get_features,
         .vhost_set_owner = vhost_kernel_set_owner,
index a01394d5ac8732f2e9270094e166ab5968ddbdcc..ec3abda9d533bf9b7c030482fde0de51e7c51a5f 100644 (file)
@@ -960,6 +960,28 @@ static void vhost_eventfd_del(MemoryListener *listener,
 {
 }
 
+static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev,
+                                                int n, uint32_t timeout)
+{
+    int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, n);
+    struct vhost_vring_state state = {
+        .index = vhost_vq_index,
+        .num = timeout,
+    };
+    int r;
+
+    if (!dev->vhost_ops->vhost_set_vring_busyloop_timeout) {
+        return -EINVAL;
+    }
+
+    r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state);
+    if (r) {
+        return r;
+    }
+
+    return 0;
+}
+
 static int vhost_virtqueue_init(struct vhost_dev *dev,
                                 struct vhost_virtqueue *vq, int n)
 {
@@ -990,7 +1012,7 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
 }
 
 int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
-                   VhostBackendType backend_type)
+                   VhostBackendType backend_type, uint32_t busyloop_timeout)
 {
     uint64_t features;
     int i, r;
@@ -1031,6 +1053,17 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
             goto fail_vq;
         }
     }
+
+    if (busyloop_timeout) {
+        for (i = 0; i < hdev->nvqs; ++i) {
+            r = vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i,
+                                                     busyloop_timeout);
+            if (r < 0) {
+                goto fail_busyloop;
+            }
+        }
+    }
+
     hdev->features = features;
 
     hdev->memory_listener = (MemoryListener) {
@@ -1073,6 +1106,11 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
     hdev->memory_changed = false;
     memory_listener_register(&hdev->memory_listener, &address_space_memory);
     return 0;
+fail_busyloop:
+    while (--i >= 0) {
+        vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i, 0);
+    }
+    i = hdev->nvqs;
 fail_vq:
     while (--i >= 0) {
         vhost_virtqueue_cleanup(hdev->vqs + i);
index 95fcc9667648554f0608be9e5ea281316f1028a6..84e1cb79ff345708a9dc942a34863c698d7545a3 100644 (file)
@@ -57,6 +57,8 @@ typedef int (*vhost_set_vring_kick_op)(struct vhost_dev *dev,
                                        struct vhost_vring_file *file);
 typedef int (*vhost_set_vring_call_op)(struct vhost_dev *dev,
                                        struct vhost_vring_file *file);
+typedef int (*vhost_set_vring_busyloop_timeout_op)(struct vhost_dev *dev,
+                                                   struct vhost_vring_state *r);
 typedef int (*vhost_set_features_op)(struct vhost_dev *dev,
                                      uint64_t features);
 typedef int (*vhost_get_features_op)(struct vhost_dev *dev,
@@ -91,6 +93,7 @@ typedef struct VhostOps {
     vhost_get_vring_base_op vhost_get_vring_base;
     vhost_set_vring_kick_op vhost_set_vring_kick;
     vhost_set_vring_call_op vhost_set_vring_call;
+    vhost_set_vring_busyloop_timeout_op vhost_set_vring_busyloop_timeout;
     vhost_set_features_op vhost_set_features;
     vhost_get_features_op vhost_get_features;
     vhost_set_owner_op vhost_set_owner;
index b60d7585b4a9c8e742bdcb2c4f32a1bae3f3a9d8..2106ed8c0de7e5724e99dc278f3be3b43a4f2a5b 100644 (file)
@@ -64,7 +64,8 @@ struct vhost_dev {
 };
 
 int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
-                   VhostBackendType backend_type);
+                   VhostBackendType backend_type,
+                   uint32_t busyloop_timeout);
 void vhost_dev_cleanup(struct vhost_dev *hdev);
 int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
 void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
index 0bd48770d81ef78bddce2e5c49444a83701a7d58..5a08efffef27dc2c37af2766e4697fa599ca8fa5 100644 (file)
@@ -10,6 +10,7 @@ typedef struct vhost_net VHostNetState;
 typedef struct VhostNetOptions {
     VhostBackendType backend_type;
     NetClientState *net_backend;
+    uint32_t busyloop_timeout;
     void *opaque;
 } VhostNetOptions;
 
index 49817c70c1e808955e509d2d6ed3677538444c9f..676bad4e1166ff7c3533055bea3c10f88e5bf403 100644 (file)
--- a/net/tap.c
+++ b/net/tap.c
@@ -663,6 +663,11 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
 
         options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
         options.net_backend = &s->nc;
+        if (tap->has_poll_us) {
+            options.busyloop_timeout = tap->poll_us;
+        } else {
+            options.busyloop_timeout = 0;
+        }
 
         if (vhostfdname) {
             vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err);
@@ -687,7 +692,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
             return;
         }
     } else if (vhostfdname) {
-        error_setg(errp, "vhostfd= is not valid without vhost");
+        error_setg(errp, "vhostfd(s)= is not valid without vhost");
     }
 }
 
index 92f4cfd1b15ae9caffd078d37d2eab8106c152cb..a88dfe065512e3fe4ecbc689ab7d79bc74b3ed20 100644 (file)
@@ -91,6 +91,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
 
         options.net_backend = ncs[i];
         options.opaque      = s->chr;
+        options.busyloop_timeout = 0;
         s->vhost_net = vhost_net_init(&options);
         if (!s->vhost_net) {
             error_report("failed to init vhost_net for queue %d", i);
index ba3bf14749a94078d3e6fc5cf6d053bc0ebe3106..d2d650673b84c18b92e69bbeccb3ab22e3958629 100644 (file)
 #
 # @queues: #optional number of queues to be created for multiqueue capable tap
 #
+# @poll-us: #optional maximum number of microseconds that could
+# be spent on busy polling for tap (since 2.7)
+#
 # Since 1.2
 ##
 { 'struct': 'NetdevTapOptions',
     '*vhostfd':    'str',
     '*vhostfds':   'str',
     '*vhostforce': 'bool',
-    '*queues':     'uint32'} }
+    '*queues':     'uint32',
+    '*poll-us':    'uint32'} }
 
 ##
 # @NetdevSocketOptions
index 9692e53af680516f26946fb8e8b55fad35fe171d..8e0d9a51bf90665d05263de616dff69c9397c873 100644 (file)
@@ -1581,6 +1581,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
     "-netdev tap,id=str[,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile]\n"
     "         [,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off]\n"
     "         [,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off][,queues=n]\n"
+    "         [,poll-us=n]\n"
     "                configure a host TAP network backend with ID 'str'\n"
     "                use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
     "                to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
@@ -1600,6 +1601,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
     "                use 'vhostfd=h' to connect to an already opened vhost net device\n"
     "                use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n"
     "                use 'queues=n' to specify the number of queues to be created for multiqueue TAP\n"
+    "                use 'poll-us=n' to speciy the maximum number of microseconds that could be\n"
+    "                spent on busy polling for vhost net\n"
     "-netdev bridge,id=str[,br=bridge][,helper=helper]\n"
     "                configure a host TAP network backend with ID 'str' that is\n"
     "                connected to a bridge (default=" DEFAULT_BRIDGE_INTERFACE ")\n"