Blame 0626-usb-redir-Add-an-already_in_flight-packet-id-queue.patch

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