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

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