9290838
From 7f3022f4ee2f83aeb0a1eea265f4bf9b4401096e Mon Sep 17 00:00:00 2001
c8dfc65
From: Hans de Goede <hdegoede@redhat.com>
c8dfc65
Date: Tue, 4 Sep 2012 17:03:54 +0200
5544c1b
Subject: [PATCH] usb-redir: Add an already_in_flight packet-id queue
c8dfc65
c8dfc65
After a live migration, the usb-hcd will re-queue all packets by
c8dfc65
walking over the schedule in the guest memory again, but requests which
c8dfc65
were encountered on the migration source before will already be in flight,
c8dfc65
so these should *not* be re-send to the usbredir-host.
c8dfc65
c8dfc65
This patch adds an already in flight packet ud queue, which will be filled by
c8dfc65
the source before migration and then moved over to the migration dest, any
c8dfc65
async handled packets are then checked against this queue to avoid sending
c8dfc65
the same packet to the usbredir-host twice.
c8dfc65
c8dfc65
Signed-off-by: Hans de Goede <hdegoede@redhat,com>
c8dfc65
---
c8dfc65
 hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++
c8dfc65
 1 file changed, 43 insertions(+)
c8dfc65
c8dfc65
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
5544c1b
index e2b8159..cdd705f 100644
c8dfc65
--- a/hw/usb/redirect.c
c8dfc65
+++ b/hw/usb/redirect.c
c8dfc65
@@ -98,6 +98,7 @@ struct USBRedirDevice {
c8dfc65
     struct usbredirparser *parser;
c8dfc65
     struct endp_data endpoint[MAX_ENDPOINTS];
c8dfc65
     struct PacketIdQueue cancelled;
c8dfc65
+    struct PacketIdQueue already_in_flight;
c8dfc65
     /* Data for device filtering */
c8dfc65
     struct usb_redir_device_connect_header device_info;
c8dfc65
     struct usb_redir_interface_info_header interface_info;
5544c1b
@@ -328,6 +329,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id)
c8dfc65
     return packet_id_queue_remove(&dev->cancelled, id);
c8dfc65
 }
c8dfc65
 
c8dfc65
+static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev,
c8dfc65
+    struct USBEndpoint *ep)
c8dfc65
+{
c8dfc65
+    static USBPacket *p;
c8dfc65
+
c8dfc65
+    QTAILQ_FOREACH(p, &ep->queue, queue) {
c8dfc65
+        packet_id_queue_add(&dev->already_in_flight, p->id);
c8dfc65
+    }
c8dfc65
+}
c8dfc65
+
c8dfc65
+static void usbredir_fill_already_in_flight(USBRedirDevice *dev)
c8dfc65
+{
c8dfc65
+    int ep;
c8dfc65
+    struct USBDevice *udev = &dev->dev;
c8dfc65
+
c8dfc65
+    usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl);
c8dfc65
+
c8dfc65
+    for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
c8dfc65
+        usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]);
c8dfc65
+        usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]);
c8dfc65
+    }
c8dfc65
+}
c8dfc65
+
c8dfc65
+static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id)
c8dfc65
+{
c8dfc65
+    return packet_id_queue_remove(&dev->already_in_flight, id);
c8dfc65
+}
c8dfc65
+
c8dfc65
 static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
c8dfc65
     uint8_t ep, uint64_t id)
c8dfc65
 {
5544c1b
@@ -543,6 +572,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
c8dfc65
 
c8dfc65
     DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id);
c8dfc65
 
c8dfc65
+    if (usbredir_already_in_flight(dev, p->id)) {
c8dfc65
+        return USB_RET_ASYNC;
c8dfc65
+    }
c8dfc65
+
c8dfc65
     bulk_packet.endpoint  = ep;
c8dfc65
     bulk_packet.length    = p->iov.size;
c8dfc65
     bulk_packet.stream_id = 0;
5544c1b
@@ -623,6 +656,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
c8dfc65
         DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
c8dfc65
                 p->iov.size, p->id);
c8dfc65
 
c8dfc65
+        if (usbredir_already_in_flight(dev, p->id)) {
c8dfc65
+            return USB_RET_ASYNC;
c8dfc65
+        }
c8dfc65
+
c8dfc65
         interrupt_packet.endpoint  = ep;
c8dfc65
         interrupt_packet.length    = p->iov.size;
c8dfc65
 
5544c1b
@@ -765,6 +802,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
c8dfc65
     USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
c8dfc65
     struct usb_redir_control_packet_header control_packet;
c8dfc65
 
c8dfc65
+    if (usbredir_already_in_flight(dev, p->id)) {
c8dfc65
+        return USB_RET_ASYNC;
c8dfc65
+    }
c8dfc65
+
c8dfc65
     /* Special cases for certain standard device requests */
c8dfc65
     switch (request) {
c8dfc65
     case DeviceOutRequest | USB_REQ_SET_ADDRESS:
5544c1b
@@ -982,6 +1023,7 @@ static int usbredir_initfn(USBDevice *udev)
c8dfc65
     dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
c8dfc65
 
c8dfc65
     packet_id_queue_init(&dev->cancelled, dev, "cancelled");
c8dfc65
+    packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight");
c8dfc65
     for (i = 0; i < MAX_ENDPOINTS; i++) {
c8dfc65
         QTAILQ_INIT(&dev->endpoint[i].bufpq);
c8dfc65
     }
5544c1b
@@ -1002,6 +1044,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
c8dfc65
     int i;
c8dfc65
 
c8dfc65
     packet_id_queue_empty(&dev->cancelled);
c8dfc65
+    packet_id_queue_empty(&dev->already_in_flight);
c8dfc65
     for (i = 0; i < MAX_ENDPOINTS; i++) {
c8dfc65
         usbredir_free_bufpq(dev, I2EP(i));
c8dfc65
     }