From b9c7f698ec784ebb55a813b93f5fa9ae59284ce0 Mon Sep 17 00:00:00 2001
From: Alon Levy <alevy@redhat.com>
Date: Mon, 3 May 2010 12:56:02 -0300
Subject: [PATCH 08/15] spice-vmc: add spice_vmc_ring_t; fix write function

RH-Author: Alon Levy <alevy@redhat.com>
Message-id: <1272891368-32706-8-git-send-email-alevy@redhat.com>
Patchwork-id: 8964
O-Subject: [RHEL-6 PATCH 07/13] spice-vmc: add spice_vmc_ring_t;
	fix write function
Bugzilla: 576488
RH-Acked-by: Arnon Gilboa <agilboa@redhat.com>
RH-Acked-by: Amit Shah <amit.shah@redhat.com>
RH-Acked-by: Juan Quintela <quintela@redhat.com>

From: alon.levy <alevy@redhat.com>

A simple ring buffer to hold data from guest until spice-server reads it.

BZ: 576488
---
 hw/spice-vmc.c |  108 ++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 67 insertions(+), 41 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/spice-vmc.c |  108 ++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 67 insertions(+), 41 deletions(-)

diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
index d563459..cf9ef72 100644
--- a/hw/spice-vmc.c
+++ b/hw/spice-vmc.c
@@ -42,6 +42,16 @@
 #define SPICE_VM_CHANNEL_GUEST_DEVICE_NAME "org.redhat.spice.0"
 #define SPICE_VM_CHANNEL_DEVICE_NAME       "spicevmc"
 
+typedef struct {
+    uint8_t  d[1024*16]; /* 16 KiB */
+    uint64_t write_pos;
+    uint64_t bytes;      /* in [0, sizeof(d)] */
+    uint64_t read_pos;
+} spice_vmc_ring_t;
+
+size_t spice_ring_read(spice_vmc_ring_t* ring, uint8_t* buf, size_t len);
+size_t spice_ring_write(spice_vmc_ring_t* ring, const uint8_t* buf, size_t len);
+
 typedef struct SpiceVMChannel {
     VirtIOSerialPort port;
     bool running;
@@ -50,15 +60,58 @@ typedef struct SpiceVMChannel {
     VDIPortPlug *plug;
 
     /* buffer the memory written by the guest until spice-server reads */
-    struct {
-        uint8    d[1024*16]; /* 16 KiB */
-        unsigned write_pos;
-        int      bytes;      /* in [0, sizeof(d)] */
-        int      read_pos;
-    } guest_out_ring;
+    spice_vmc_ring_t guest_out_ring;
 } SpiceVMChannel;
 
 /*
+ * ring buffer
+ */
+
+size_t spice_ring_read(spice_vmc_ring_t* ring, uint8_t* buf, size_t len)
+{
+    size_t actual_read = MIN(len, ring->bytes);
+    size_t first_part;
+    if (actual_read > 0) {
+        if (actual_read + ring->read_pos > sizeof(ring->d)) {
+            /* two parts */
+            first_part = sizeof(ring->d) - ring->read_pos;
+            memcpy(buf, ring->d + ring->read_pos, first_part);
+            memcpy(buf + first_part, ring->d, actual_read - first_part);
+            ring->read_pos = actual_read - first_part;
+        } else {
+            /* one part */
+            memcpy(buf, ring->d + ring->read_pos, actual_read);
+            ring->read_pos += actual_read;
+        }
+        ring->bytes -= actual_read;
+    }
+    return actual_read;
+}
+
+size_t spice_ring_write(spice_vmc_ring_t* ring, const uint8_t* buf, size_t len)
+{
+    size_t bytes_written = 0;
+    size_t first_part;
+    if (ring->bytes == sizeof(ring->d)) {
+        return 0;
+    }
+    bytes_written = MIN(sizeof(ring->d) - ring->bytes, len);
+    if (ring->write_pos + bytes_written > sizeof(ring->d)) {
+        /* two parts */
+        first_part = sizeof(ring->d) - ring->write_pos;
+        memcpy(ring->d + ring->write_pos, buf, first_part);
+        memcpy(ring->d, buf + first_part, bytes_written - first_part);
+        ring->write_pos = bytes_written - first_part;
+    } else {
+        /* one part */
+        memcpy(ring->d + ring->write_pos, buf, bytes_written);
+        ring->write_pos += bytes_written;
+    }
+    ring->bytes += bytes_written;
+    return bytes_written;
+}
+
+/*
  * VDIPortInterface callbacks
  */
 
@@ -85,7 +138,7 @@ static void spice_vmc_interface_unplug(
     /* XXX - throw away anything the client has not read */
 
     if (svc->guest_out_ring.bytes != 0) {
-        printf("warning: %s: %d unwritten bytes discarded.\n",
+        printf("warning: %s: %lu unwritten bytes discarded.\n",
                             __func__, svc->guest_out_ring.bytes);
     }
     svc->guest_out_ring.read_pos = svc->guest_out_ring.write_pos;
@@ -115,25 +168,10 @@ static int spice_vmc_interface_write(
 static int spice_vmc_interface_read(
     VDIPortInterface *port, VDObjectRef plug, uint8_t *buf, int len)
 {
+    int actual_read;
     SpiceVMChannel *svc = container_of(port, SpiceVMChannel, interface);
-    int actual_read = MIN(len, svc->guest_out_ring.bytes);
 
-    if (actual_read > 0) {
-        if (actual_read + svc->guest_out_ring.read_pos > sizeof(svc->guest_out_ring.d)) {
-            // two parts
-            int first_part = sizeof(svc->guest_out_ring.d) - svc->guest_out_ring.read_pos;
-            memcpy(buf, svc->guest_out_ring.d + svc->guest_out_ring.read_pos,
-                   first_part);
-            memcpy(buf + first_part, svc->guest_out_ring.d, actual_read - first_part);
-            svc->guest_out_ring.read_pos = actual_read - first_part;
-        } else {
-            // one part
-            memcpy(buf, svc->guest_out_ring.d + svc->guest_out_ring.read_pos,
-                   actual_read);
-            svc->guest_out_ring.read_pos += actual_read;
-        }
-        svc->guest_out_ring.bytes -= actual_read;
-    }
+    actual_read = spice_ring_read(&(svc->guest_out_ring), buf, len);
     return actual_read;
 }
 
@@ -211,26 +249,14 @@ static void spice_vmc_have_data(
                 VirtIOSerialPort *port, const uint8_t *buf, size_t len)
 {
     SpiceVMChannel *svc = DO_UPCAST(SpiceVMChannel, port, port);
+    int bytes_written;
 
-    if (svc->guest_out_ring.bytes == sizeof(svc->guest_out_ring.d)) {
-        printf("WARNING: %s: throwing away %lu bytes due to ring being full\n",
-            __func__, len);
+    bytes_written = spice_ring_write(&(svc->guest_out_ring), buf, len);
+    if (bytes_written != len) {
+        printf("WARNING: %s: threw away %lu bytes due to ring being full\n",
+            __func__, (len - bytes_written));
         return;
     }
-    int bytes_read = MIN(sizeof(svc->guest_out_ring.d) - svc->guest_out_ring.bytes, len);
-    if (svc->guest_out_ring.write_pos + bytes_read > sizeof(svc->guest_out_ring.d)) {
-        /* two parts */
-        size_t first_part = sizeof(svc->guest_out_ring.d) - svc->guest_out_ring.write_pos;
-        memcpy(svc->guest_out_ring.d + svc->guest_out_ring.write_pos, buf, first_part);
-        memcpy(svc->guest_out_ring.d, buf + first_part, bytes_read - first_part);
-        svc->guest_out_ring.write_pos = bytes_read - first_part;
-    } else {
-        /* one part */
-        memcpy(svc->guest_out_ring.d + svc->guest_out_ring.write_pos, buf, bytes_read);
-        svc->guest_out_ring.write_pos += bytes_read;
-    }
-    svc->guest_out_ring.bytes += bytes_read;
-    // wakeup spice
     if (svc->plug) {
         svc->plug->wakeup(svc->plug);
     }
-- 
1.7.0.3

