Blame SOURCES/kvm-io-get-rid-of-bounce-buffering-in-websock-write-path.patch

4a2fec
From 4550459a8e915a74dfbeb97ab4b645f72165079c Mon Sep 17 00:00:00 2001
4a2fec
From: "Daniel P. Berrange" <berrange@redhat.com>
4a2fec
Date: Wed, 20 Dec 2017 17:56:58 +0100
4a2fec
Subject: [PATCH 18/42] io: get rid of bounce buffering in websock write path
4a2fec
4a2fec
RH-Author: Daniel P. Berrange <berrange@redhat.com>
4a2fec
Message-id: <20171220175702.29663-17-berrange@redhat.com>
4a2fec
Patchwork-id: 78469
4a2fec
O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 16/20] io: get rid of bounce buffering in websock write path
4a2fec
Bugzilla: 1518649
4a2fec
RH-Acked-by: John Snow <jsnow@redhat.com>
4a2fec
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
4a2fec
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
4a2fec
Currently most outbound I/O on the websock channel gets copied into the
4a2fec
rawoutput buffer, and then immediately copied again into the encoutput
4a2fec
buffer, with a header prepended. Now that qio_channel_websock_encode
4a2fec
accepts a struct iovec, we can trivially remove this bounce buffering
4a2fec
and write directly to encoutput.
4a2fec
4a2fec
In doing so, we also now correctly validate the encoutput size against
4a2fec
the QIO_CHANNEL_WEBSOCK_MAX_BUFFER limit.
4a2fec
4a2fec
Reviewed-by: Eric Blake <eblake@redhat.com>
4a2fec
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
4a2fec
(cherry picked from commit 8dfd5f96515ca20c4eb109cb0ee28e2bb32fc505)
4a2fec
4a2fec
NB, include of iov.h was pushed into previous patch to fix bisect
4a2fec
buld.
4a2fec
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 include/io/channel-websock.h |  1 -
4a2fec
 io/channel-websock.c         | 63 +++++++++++++++++++-------------------------
4a2fec
 2 files changed, 27 insertions(+), 37 deletions(-)
4a2fec
4a2fec
diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h
4a2fec
index 3762707..a7e5e92 100644
4a2fec
--- a/include/io/channel-websock.h
4a2fec
+++ b/include/io/channel-websock.h
4a2fec
@@ -59,7 +59,6 @@ struct QIOChannelWebsock {
4a2fec
     Buffer encinput;
4a2fec
     Buffer encoutput;
4a2fec
     Buffer rawinput;
4a2fec
-    Buffer rawoutput;
4a2fec
     size_t payload_remain;
4a2fec
     size_t pong_remain;
4a2fec
     QIOChannelWebsockMask mask;
4a2fec
diff --git a/io/channel-websock.c b/io/channel-websock.c
4a2fec
index 11b6039..e82b1be 100644
4a2fec
--- a/io/channel-websock.c
4a2fec
+++ b/io/channel-websock.c
4a2fec
@@ -634,19 +634,22 @@ static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error **);
4a2fec
 static void qio_channel_websock_write_close(QIOChannelWebsock *ioc,
4a2fec
                                             uint16_t code, const char *reason)
4a2fec
 {
4a2fec
-    struct iovec iov;
4a2fec
-    buffer_reserve(&ioc->rawoutput, 2 + (reason ? strlen(reason) : 0));
4a2fec
-    *(uint16_t *)(ioc->rawoutput.buffer + ioc->rawoutput.offset) =
4a2fec
-        cpu_to_be16(code);
4a2fec
-    ioc->rawoutput.offset += 2;
4a2fec
+    struct iovec iov[2] = {
4a2fec
+        { .iov_base = &code, .iov_len = sizeof(code) },
4a2fec
+    };
4a2fec
+    size_t niov = 1;
4a2fec
+    size_t size = iov[0].iov_len;
4a2fec
+
4a2fec
+    cpu_to_be16s(&code);
4a2fec
+
4a2fec
     if (reason) {
4a2fec
-        buffer_append(&ioc->rawoutput, reason, strlen(reason));
4a2fec
+        iov[1].iov_base = (void *)reason;
4a2fec
+        iov[1].iov_len = strlen(reason);
4a2fec
+        size += iov[1].iov_len;
4a2fec
+        niov++;
4a2fec
     }
4a2fec
-    iov.iov_base = ioc->rawoutput.buffer;
4a2fec
-    iov.iov_len = ioc->rawoutput.offset;
4a2fec
     qio_channel_websock_encode(ioc, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE,
4a2fec
-                               &iov, 1, iov.iov_len);
4a2fec
-    buffer_reset(&ioc->rawoutput);
4a2fec
+                               iov, niov, size);
4a2fec
     qio_channel_websock_write_wire(ioc, NULL);
4a2fec
     qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
4a2fec
 }
4a2fec
@@ -894,7 +897,6 @@ static void qio_channel_websock_finalize(Object *obj)
4a2fec
     buffer_free(&ioc->encinput);
4a2fec
     buffer_free(&ioc->encoutput);
4a2fec
     buffer_free(&ioc->rawinput);
4a2fec
-    buffer_free(&ioc->rawoutput);
4a2fec
     object_unref(OBJECT(ioc->master));
4a2fec
     if (ioc->io_tag) {
4a2fec
         g_source_remove(ioc->io_tag);
4a2fec
@@ -1104,8 +1106,8 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc,
4a2fec
                                           Error **errp)
4a2fec
 {
4a2fec
     QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
4a2fec
-    size_t i;
4a2fec
-    ssize_t done = 0;
4a2fec
+    ssize_t want = iov_size(iov, niov);
4a2fec
+    ssize_t avail;
4a2fec
     ssize_t ret;
4a2fec
 
4a2fec
     if (wioc->io_err) {
4a2fec
@@ -1118,32 +1120,21 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc,
4a2fec
         return -1;
4a2fec
     }
4a2fec
 
4a2fec
-    for (i = 0; i < niov; i++) {
4a2fec
-        size_t want = iov[i].iov_len;
4a2fec
-        if ((want + wioc->rawoutput.offset) > QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
4a2fec
-            want = (QIO_CHANNEL_WEBSOCK_MAX_BUFFER - wioc->rawoutput.offset);
4a2fec
-        }
4a2fec
-        if (want == 0) {
4a2fec
-            goto done;
4a2fec
-        }
4a2fec
-
4a2fec
-        buffer_reserve(&wioc->rawoutput, want);
4a2fec
-        buffer_append(&wioc->rawoutput, iov[i].iov_base, want);
4a2fec
-        done += want;
4a2fec
-        if (want < iov[i].iov_len) {
4a2fec
-            break;
4a2fec
-        }
4a2fec
+    avail = wioc->encoutput.offset >= QIO_CHANNEL_WEBSOCK_MAX_BUFFER ?
4a2fec
+        0 : (QIO_CHANNEL_WEBSOCK_MAX_BUFFER - wioc->encoutput.offset);
4a2fec
+    if (want > avail) {
4a2fec
+        want = avail;
4a2fec
     }
4a2fec
 
4a2fec
- done:
4a2fec
-    if (wioc->rawoutput.offset) {
4a2fec
-        struct iovec iov = { .iov_base = wioc->rawoutput.buffer,
4a2fec
-                             .iov_len = wioc->rawoutput.offset };
4a2fec
+    if (want) {
4a2fec
         qio_channel_websock_encode(wioc,
4a2fec
                                    QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME,
4a2fec
-                                   &iov, 1, iov.iov_len);
4a2fec
-        buffer_reset(&wioc->rawoutput);
4a2fec
+                                   iov, niov, want);
4a2fec
     }
4a2fec
+
4a2fec
+    /* Even if want == 0, we'll try write_wire in case there's
4a2fec
+     * pending data we could usefully flush out
4a2fec
+     */
4a2fec
     ret = qio_channel_websock_write_wire(wioc, errp);
4a2fec
     if (ret < 0 &&
4a2fec
         ret != QIO_CHANNEL_ERR_BLOCK) {
4a2fec
@@ -1153,11 +1144,11 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc,
4a2fec
 
4a2fec
     qio_channel_websock_set_watch(wioc);
4a2fec
 
4a2fec
-    if (done == 0) {
4a2fec
+    if (want == 0) {
4a2fec
         return QIO_CHANNEL_ERR_BLOCK;
4a2fec
     }
4a2fec
 
4a2fec
-    return done;
4a2fec
+    return want;
4a2fec
 }
4a2fec
 
4a2fec
 static int qio_channel_websock_set_blocking(QIOChannel *ioc,
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec